// zeal - A portable Glk-based Z-code interpreter
// Copyright (C) 2000 Jeremy Condit <jcondit@eecs.harvard.edu>
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

// =======================================================================
//  zeal.cc:
//
//  this module contains only the glk_main function, which is the initial
//  entry point for zeal.
// =======================================================================

#include "zeal.h"
#include "error.h"
#include "iface.h"
#include "osdep.h"
#include "random.h"
#include "machine.h"

machine* m = NULL;
osdep* os = NULL;
iface* io = NULL;

game_state* initial = NULL;

// glk_main
//
// you are standing in an open field west of a big pile of code...

void
glk_main()
{
    // if startup procedures didn't make us an osdep structure,
    // create a generic one
    if (os == NULL) {
        os = new osdep;
        MEMCHECK(os);
    }

    // seed the rng
    sgenrand(os->get_seed());

    // get the story file from the startup code
    strid_t story = os->get_story();

    if (story == NULL) {
        // no story file?  ask the user for one
        frefid_t f = glk_fileref_create_by_prompt(fileusage_Data,
                                                  filemode_Read, 0);
        if (f != NULL) {
            story = glk_stream_open_file(f, filemode_Read, 0);
            glk_fileref_destroy(f);
        }

        ASSERT_MSG(story != NULL, "Couldn't open story file.");

        m = new machine(story);
        MEMCHECK(m);
        glk_stream_close(story, NULL);
    } else {
        m = new machine(story);
        MEMCHECK(m);
        os->close_story();
    }

    initial = new game_state(*m);
    MEMCHECK(initial);

    // set style hints--we use user1 and user2 for bold and italic
    // (see iface.cc)
    glk_stylehint_set(wintype_TextBuffer, style_User1, stylehint_Weight, 1);
    glk_stylehint_set(wintype_TextBuffer, style_User2, stylehint_Oblique, 1);

    // open the main window
    winid_t main_win = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
    ASSERT(main_win != NULL);
    io = new iface(main_win, os->get_strictz());
    MEMCHECK(io);

    // initialize the header in memory
    m->set_header();

    // main loop: execute instructions until we're halted
    while (!m->halted()) {
        glk_tick();
        io->check_transcript();

        if (io->blocked() && !m->interrupted()) {
            // if we're blocked on i/o, wait for an event and hand it off
            // for processing
            event_t ev;
            glk_select(&ev);
            io->process_event(&ev);
        } else {
            // otherwise, just execute the next instruction
            m->one_inst();
        }
    }
}
