/*
 * Implementation of the Printer User Interface Dialogs
 *
 * Copyright 2006-2007 Detlef Riekenberg
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#define COBJMACROS
#define NONAMELESSUNION

#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winreg.h"
#include "winver.h"
#include "winnls.h"
#include "shellapi.h"

#include "wine/unicode.h"
#include "wine/debug.h"
#include "printui_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(printui);

static HINSTANCE PRINTUI_hInstance = NULL;

/* ################################# */

/* Must be in order with OPT_*      */
static const WCHAR optionsW[OPT_MAX+1]={'a','b','c','f','h','j','l','m','n','t','r','v',0};

/* Must be in order with FLAG_*     */
static const WCHAR flagsW[FLAG_MAX+1]={'q','w','y','z','Z',0};


/* ################################
 * get_next_wstr() [Internal]
 *
 * Get the next WSTR, when available
 *
 */

static LPWSTR get_next_wstr(context_t * cx)
{
    LPWSTR  ptr;

    ptr = cx->pNextCharW;
    if (ptr && ptr[0]) {
        cx->pNextCharW = NULL;
        return ptr;
    }

    /* Get the next Parameter, when available */
    if (cx->next_arg < cx->argc) {
        ptr = cx->argv[cx->next_arg];
        cx->next_arg++;
        cx->pNextCharW = NULL;
        return ptr;
    }
    return NULL;
}


/* ################################
 * get_next_wchar() [Internal]
 *
 * Get the next WCHAR from the Commandline or from the File (@ Filename)
 *
 * ToDo: Support Parameter from a File ( "@Filename" )
 *
 */

static WCHAR get_next_wchar(context_t * cx, BOOL use_next_parameter)
{
    WCHAR   c;

    /* Try the next WCHAR in the actual Parameter */
    if (cx->pNextCharW) {
        c = *cx->pNextCharW;
        if (c) {
            cx->pNextCharW++;
            return c;
        }
        /* We reached the end of the Parameter */
        cx->pNextCharW = NULL;
    }

    /* Get the next Parameter, when available and allowed */
    if ((cx->pNextCharW == NULL) && (cx->next_arg < cx->argc) && (use_next_parameter)) {
        cx->pNextCharW = cx->argv[cx->next_arg];
        cx->next_arg++;
    }

    if (cx->pNextCharW) {
        c = *cx->pNextCharW;
        if (c) {
            cx->pNextCharW++;
        }
        else
        {
            /* We reached the end of the Parameter */
            cx->pNextCharW = NULL;
        }
        return c;
    }
    return '\0';
}

/* ################################ */
static BOOL parse_rundll(context_t * cx)
{
    LPWSTR  ptr;
    DWORD   index;
    WCHAR   txtW[2];
    WCHAR   c;


    c = get_next_wchar(cx, TRUE);
    txtW[1] = '\0';

    while (c)
    {

        while ( (c == ' ') || (c == '\t'))
        {
            c = get_next_wchar(cx, TRUE);
        }
        txtW[0] = c;

        if (c == '@') {
            /* read commands from a File */
            ptr = get_next_wstr(cx);
            FIXME("redir not supported: %s\n", debugstr_w(ptr));
            return FALSE;
        }
        else if (c == '/') {
            c = get_next_wchar(cx, FALSE);
            while ( c )
            {
                txtW[0] = c;
                ptr = strchrW(optionsW, c);
                if (ptr) {
                    index = ptr - optionsW;
                    cx->options[index] = get_next_wstr(cx);
                    TRACE(" opt: %s  %s\n", debugstr_w(txtW), debugstr_w(cx->options[index]));
                    c = 0;
                }
                else
                {
                    ptr = strchrW(flagsW, c);
                    if (ptr) {
                        index = ptr - flagsW;
                        cx->flags[index] = TRUE;
                        TRACE("flag: %s\n", debugstr_w(txtW));
                    }
                    else
                    {
                        cx->command = c;
                        cx->subcommand = '\0';
                        TRACE(" cmd: %s\n", debugstr_w(txtW));
                    }

                    /* help has priority over all commands */
                    if (c == '?') {
                        return TRUE;
                    }

                    c = get_next_wchar(cx, FALSE);

                    /* Some commands use two wchar */
                    if ((cx->command == 'd') || (cx->command == 'g') || (cx->command == 'i') ||
                        (cx->command == 'S') || (cx->command == 'X') ){
                        cx->subcommand = c;
                        txtW[0] = c;
                        TRACE(" sub: %s\n", debugstr_w(txtW));
                        c = get_next_wchar(cx, FALSE);
                    }
                }
            }
            c = get_next_wchar(cx, TRUE);

        }
        else
        {
            /* The commands 'S' and 'X' have additional Parameter */
            if ((cx->command == 'S') || (cx->command == 'X')) {

                /* the actual WCHAR is the start from the extra Parameter */
                cx->pNextCharW--;
                TRACE("%d extra Parameter, starting with %s\n", 1 + (cx->argc - cx->next_arg), debugstr_w(cx->pNextCharW));
                return TRUE;
            }
            FIXME("0x%x: %s is unknown\n", c, debugstr_wn(&c, 1));
            return FALSE;
        }

    }
    return TRUE;
}

/*****************************************************
 *      DllMain
 */
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);

    switch(fdwReason)
    {
        case DLL_WINE_PREATTACH:
            return FALSE;           /* prefer native version */

        case DLL_PROCESS_ATTACH:
            PRINTUI_hInstance = hinstDLL;
            DisableThreadLibraryCalls( hinstDLL );
            break;
    }
    return TRUE;
}


/*****************************************************
 *  PrintUIEntryW                [printui.@]
 *  Commandline-Interface for using printui.dll with rundll32.exe
 *
 */
void WINAPI PrintUIEntryW(HWND hWnd, HINSTANCE hInst, LPCWSTR pCommand, DWORD nCmdShow)
{
    context_t cx;
    BOOL  res = FALSE;

    TRACE("(%p, %p, %s, 0x%x)\n", hWnd, hInst, debugstr_w(pCommand), nCmdShow);

    memset(&cx, 0, sizeof(context_t));
    cx.hWnd = hWnd;
    cx.nCmdShow = nCmdShow;

    if ((pCommand) && (pCommand[0])) {
        /* result is allocated with GlobalAlloc() */
        cx.argv = CommandLineToArgvW(pCommand, &cx.argc);
        TRACE("got %d args at %p\n", cx.argc, cx.argv);

        res = parse_rundll(&cx);
    }

    if (res && cx.command) {
        switch (cx.command)
        {

            default:
            {
                WCHAR   txtW[3];
                txtW[0] = cx.command;
                txtW[1] = cx.subcommand;
                txtW[2] = '\0';
                FIXME("command not implemented: %s\n", debugstr_w(txtW));
            }
        }
    }

    if ((res == FALSE) || (cx.command == '\0')) {
        FIXME("dialog: Printer / The operation was not successful\n");
    }

    GlobalFree(cx.argv);

}