/*   _____________________________________________________________
    /                                                             \
    | Module:   windows base module
    \_____________________________________________________________/

    contents:

        Windows startup code,
        which does Windows specific stuff.

        Let me stress that the whole game is written

          * * * ANTI WINDOWS CONFORM * * *

        (therefore the high performance :-)

        ... on the first WM_PAINT received,
            BeginPaint() is done and then mymain() is called.
            That's it, there is no EndPaint() before the program ends,
            so there IS no Windows message processing.

    Developers: ID: Name:
    =========== --- -----
                JTH Juergen Thumm
  _____________________________________/VERSION HISTORY\____________________
 /Date_ Who What____________________________________________________________\
 yymmdd --- -----------------------------------------------------------------
 950311 JTH windows cmdline parameters: promote to mymain
*/

#include "global.h"

InstanceBase& ibase = explib_root.ibase;

HWND    extwin = 0; // extended window handle

// application header, also used by resource compiler

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

/*   _____________________________________________________________
    /                                                             \
    | Function: InstanceBase::InitFirstInst - initialize first instance of a program
    \_____________________________________________________________/

    Descriptn:  when program gots started 1st time, some extra inits are done here

    Returncode: 0   = success
                else  failure

    Called by:  WinMain

    Calls:      RegisterClass() of Windows

    Notes:
        ...
*/

sysint InstanceBase::InitFirstInst(HINSTANCE inst, HINSTANCE previnst, sysint cmdshow)
{
    WNDCLASS    mainwc; // registering template for main windows's class

    ibase.instcnt   = 1;    // this is instance number one

    strncpy(ibase.appname, "Zone of Thunder", sizeof(ibase.appname));

    // fill up the main window's class description

    mainwc.lpszClassName    = ibase.appname;
    mainwc.hInstance        = inst;
    mainwc.lpfnWndProc      = WndProc;                  // ptr to message scheduler
    mainwc.style            = CS_HREDRAW|CS_VREDRAW;
    mainwc.lpszMenuName     = (LPSTR)NULL;                  // no menu
    mainwc.hCursor          = LoadCursor(NULL, IDC_ARROW);  // load mouse pointer
    mainwc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);  // default icon
    mainwc.hbrBackground    = (HBRUSH)GetStockObject(WHITE_BRUSH);
    mainwc.cbClsExtra       = 0;    // no extra bytes
    mainwc.cbWndExtra       = 0;    // no extra bytes

    // now let this register

    return  (RegisterClass(&mainwc));
}

/*   _____________________________________________________________
    /                                                             \
    | Function: WinMain - entry point for every program instance
    \_____________________________________________________________/

    Descriptn:  this performs basic inits common to all windows applications

    Returncode: 'param' of the last processed message or NULL in error case

    Called by:  Windows 3.1

    Calls:      init routines and then Windows 3.1 again which will then
                call us again as soon as there are messages for us

    Notes:
*/

LPSTR WinCmdLine = 0;

sysint PASCAL WinMain
                  ( HINSTANCE inst,     // this (new) instance's handle
                    HINSTANCE previnst, // handle of previous instance
                    LPSTR   cmdline,    // additional command line parameters
                    sysint  cmdshow     // how should window be displayed initially
                  )
{
 MSG    msg;    // current message in message loop

    WinCmdLine  = cmdline;

#ifdef ZOTHREL
    int RunMode = RootBase::NOLOG;
#else
    int RunMode = RootBase::DEBUG;
#endif

    ROOTNAME.Prolog (   0, 0,      // argc, argv
                        "log.tmp", // logfile name
                        RunMode    // debug mode
                    );

    if(!previnst)
    {
        // init primar instance

        if(!ibase.InitFirstInst(inst, previnst, cmdshow))
        {
            return NULL;
        }
    }
    else
    {
        // init further instances

        // this may include copying data from previous instances

        GetInstanceData(previnst, ibase.appname, 20);
        GetInstanceData(previnst, (PSTR)&ibase.instcnt, sizeof(int));
        ibase.instcnt++;
    }

    // all-instances init stuff

    ibase.inst      = inst;

    // adapt field size to desktop

    RECT rdesk;
    GetWindowRect(GetDesktopWindow(), &rdesk);
    field.opt.openwidth  = rdesk.right  - rdesk.left;
    field.opt.openheight = rdesk.bottom - rdesk.top;
    if(field.opt.openwidth  < 640)  field.opt.openwidth  = 640;
    if(field.opt.openheight < 480)  field.opt.openheight = 480;

    // read configuration, if any

    short   dyOpen  = 0;    // y delta on window creation

    FILE    *cf;

#   define IFKEY(x) if(!stricmp(tok, #x))

    if(cf = fopen("zoth.ini","r"))
    {
        char    buf[80];
        char    *tok,*vtok,*tokend;
        ulong   value;
        ushort  icolor, rgb;

        while(fgets(buf, sizeof(buf) - 2, cf))
        {

    // === per line of file ===

    if(!buf[0] || buf[0] == ';' || buf[0] == '\n')
        continue;

    // split line into key and value

    tok = strtok(buf, " \t;\n");
    if(!tok)
        continue;

    vtok = strtok(0, " \t;\n");
    if(!vtok)
        continue;

    value   = strtol(vtok, &tokend, 0);

    // pmsg("key >%s< value >%s< %lu %lxh", tok,vtok,value,value);

    // handle keywords

    IFKEY(humans)
    {
        field.num.humans    = min(value,2);
        field.num.players   =
            field.num.humans + field.num.robots;
    }

    IFKEY(robots)
    {
        field.num.robots    = min(value,50);
        field.num.players   =
            field.num.humans + field.num.robots;
    }

    IFKEY(swapsticks)   field.opt.swapsticks    = value;
    IFKEY(weaksupport)  justice.active          = value;
    IFKEY(stereo)       field.opt.stereo        = value;

    IFKEY(music)
        switch(value)
        {
            case 0: field.opt.nomusic = 1; field.opt.alwaysmusic = 0; break;
            case 1: field.opt.nomusic = 0; field.opt.alwaysmusic = 0; break;
            case 2: field.opt.nomusic = 0; field.opt.alwaysmusic = 1; break;
        }

    IFKEY(khz)
    {
        switch(value)
        {
            case     0:
            case    11:
            case    22:
            case    32:
                field.opt.khz   = value;
                break;
        }
    }

    IFKEY(timing)   field.taddspeed         = min(value,9);
    IFKEY(weapons)  field.opt.cxw           = value;
    IFKEY(playmode) field.opt.playmode      = value;
    IFKEY(magic)    field.opt.magic         = value;
    IFKEY(clock)    field.opt.showxinfos    = (value&3)<<1;

    IFKEY(width)    field.opt.openwidth     = max(value, 320);
    IFKEY(height)   field.opt.openheight    = max(value, 200);

    IFKEY(yshift)   dyOpen          = 0 - (short)value;

    IFKEY(swappixcol)   field.opt.swappixcol    = value & 1;
    // this is promoted in main() into pixeldisplay.

    IFKEY(usepalette)   field.opt.usewinpal     = value & 1;
    // influences first usePalette() call in zoth.cpp

    IFKEY(tlasershape)  field.opt.tlaser    = value & (TLASER_SHAPES-1);

    // popular colors:

    IFKEY(colback1)     field.startcols[col_backgrnd ]  = value;
    IFKEY(colback2)     field.startcols[col_backgrnd2]  = value;
    IFKEY(colback3)     field.startcols[col_backgrnd3]  = value;

    IFKEY(coltlaser1)   field.startcols[col_tlaser0]    = value;
    IFKEY(coltlaser2)   field.startcols[col_tlaser1]    = value;
    IFKEY(coltlaser3)   field.startcols[col_tlaser2]    = value;

    // undocumented:

    IFKEY(color)
    {
        icolor  = (ushort)(value >> 16);
        rgb     = (ushort)value & 0x0FFFU;

        if(icolor < PF_NUMPRESCOLS)
            field.startcols[icolor] = rgb;
    }

    IFKEY(logfile)
    {
        if(value)
            field.opt.debugmode |= ZDEB_ALLOWLOGFILE;
    }

    IFKEY(glps)
    {
        if(value)
            field.opt.debugmode &= (~0 ^ ZDEB_SHOWBITMAPS);
    }

    IFKEY(showsounds)
    {
        if(value)
            field.opt.debugmode |= ZDEB_SHOWSOUNDS;
    }

    IFKEY(savermat)     // save rotation matrix
    {
       extern bool bGlobalAllowRMatSave;
       bGlobalAllowRMatSave = 1;
    }

    IFKEY(defineshape)
    {
        extern void pokeShape(  ushort  shapenumber,
                                ushort  xfaces,
                                cpix    xmaxsize,
                                ushort  xnrot,
                                ushort  xnzoom,
                                ulong   xflags  );

        ushort snumber  = value;
        ushort sfaces   = 0;
        cpix   smaxsize = 0;
        ushort snrot    = 0;
        ushort snzoom   = 0;
        ulong  sflags   = ULONG_MAX;

        if(vtok && (vtok = strtok(0, " \t;\n")))    sfaces   = atol(vtok);
        if(vtok && (vtok = strtok(0, " \t;\n")))    smaxsize = atol(vtok);
        if(vtok && (vtok = strtok(0, " \t;\n")))    snrot    = atol(vtok);
        if(vtok && (vtok = strtok(0, " \t;\n")))    snzoom   = atol(vtok);
        if(vtok && (vtok = strtok(0, " \t;\n")))    sflags   = atol(vtok);

        if(sflags < ULONG_MAX)
            pokeShape(snumber, sfaces, smaxsize, snrot, snzoom, sflags);
    }

    //  === ===

        }   // endwhile (lines from file)

        fclose(cf);
    }

    // create 'extended' window which will be painted black

    extwin      =   CreateWindow(   ibase.appname,  // window class name
                                    ibase.appname,  // main window name

                                    0,

                                    0,   // CW_USEDEFAULT default x-posn
                                    field.opt.openheight - 60 - dyOpen, // ypos
                                    field.opt.openwidth, // default width
                                    100, // default window height
                                    NULL,           // no parent window
                                    NULL,           // use class menu
                                    ibase.inst,     // this app's instance
                                    NULL);          // no extra parms

    if(extwin)
    {
        ShowWindow(extwin, cmdshow);
        UpdateWindow(extwin);
    }
    //  else if extwin can't open, don't mind

    // create main window

    ibase.mainwin   = CreateWindow( ibase.appname,  // window class name
                                    ibase.appname,  // main window name
                                    0,      // WS_OVERLAPPED | WS_SYSMENU,
                                    0,              // x-posn
                                    -20 - dyOpen,   // y-posn
                                    field.opt.openwidth,    // width
                                    field.opt.openheight,   // height
                                    NULL,           // no parent window
                                    NULL,           // use class menu
                                    ibase.inst,     // this app's instance
                                    NULL);          // no extra parms

    if(!ibase.mainwin)

        return  0;

    ShowWindow(ibase.mainwin, cmdshow);
    UpdateWindow(ibase.mainwin);

    // ------------------------------------------------------
    // ---  message loop
    // ------------------------------------------------------

    while(GetMessage((LPMSG)&msg, NULL, 0, 0))
    {
        TranslateMessage((LPMSG)&msg);      // e.g. translate keycodes
        DispatchMessage((LPMSG)&msg);       // this may call WndProc
    }

    // got a 'QUIT' message

    return  (msg.wParam);   // end application, return to desktop
}

// ==========================================================================
// === application code
// ==========================================================================

void mymain(char* cmdline);
void PaintBlack(HWND win);

LRESULT CALLBACK WndProc
                            (   HWND    win,    // window
                                UINT    msg,    // message code
                                WPARAM  wparm,  // message word parameter
                                LPARAM  lparm   // message long parameter
                            )
{
    switch(msg)
    {
        case    WM_PAINT:               // redraw client area

                if(win == ibase.mainwin)
                    mymain(WinCmdLine); // just once then fall through:
                else
                {
                    PaintBlack(win);
                    break;
                }

        case    WM_DESTROY:             // windows destruction request

                PostQuitMessage(0);     // send ourselves a WM_QUIT

                break;

        default:                        // all other msg's to default handler
                return(DefWindowProc(win, msg, wparm, lparm));
    }

    return 0L;
}

void PaintBlack(HWND win)
{
    PAINTSTRUCT ps;
    HBRUSH      brush;
    HDC         hdc;

    ifn(hdc = BeginPaint(win, &ps)) return;

    if(brush = GetStockObject(BLACK_BRUSH))
    {
        RECT rect;

        rect.left   = 0;
        rect.top    = 0;
        rect.right  = field.opt.openwidth;
        rect.bottom = 80;

        FillRect(hdc, &rect, brush);

        DeleteObject(brush);
    }

    EndPaint(win, &ps);
}
