/////////////////////////////////////////////////////////////////////////////
// Name:        utils.cpp
// Purpose:     wxWidgets command-line Package Manager and Packager utils
// Author:      Francesco Montorsi
// Modified by:
// Created:     2006-11-08
// RCS-ID:      $Id: utils.cpp,v 1.3 2007/01/25 18:51:50 frm Exp $
// Copyright:   (c) Francesco Montorsi
// Licence:     wxWidgets license
/////////////////////////////////////////////////////////////////////////////


// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#include <wx/cmdline.h>
#include <wx/config.h>
#include <wx/stdpaths.h>

#include "wxp/packagewxp.h"
#include "wx/md5.h"

// wxP own headers
#include "symbols.h"
#include "app.h"


// ----------------------------------------------------------------------------
// global utils
// ----------------------------------------------------------------------------

class wxConsoleDownloadThread : public wxDownloadThread
{
public:
    wxConsoleDownloadThread() {}

    void OnUpdate()
    {
        if (m_nFinalSize == wxInvalidSize)
        {
            // we cannot know how much we progressed...
            wxPrintf(wxT("."));
            return;
        }

        // we will print a total of 20 dots to indicate that the download has been completed
        int currPos = (int)(16 * m_nCurrentSize.ToDouble() / m_nFinalSize.ToDouble());
        for (int i=m_lastPos; i <= currPos; i++)
        {
            if ( (i % 4) == 0 )
                wxPrintf(wxT(" %d%% "), (i/4)*25);
            else
                wxPrintf(wxT("."));
        }

        m_lastPos = currPos + 1;
    }

    void OnAbort()
    {
        if (m_pSuccess) *m_pSuccess = false;
        if (m_pExist) *m_pExist = false;
        wxPrintf(wxT("!!! ERROR: download aborted\n"));
    }

    void OnUserAbort()
    {
        if (m_pSuccess) *m_pSuccess = false;
        if (m_pExist) *m_pExist = false;
    }

    void OnComplete()
    {
        if (m_pSuccess) *m_pSuccess = true;
        if (m_pExist) *m_pExist = false;
        wxPrintf(wxT("<= Download complete\n"));
    }

    bool Download(const wxString &url, wxOutputStream *stream, 
                  volatile bool *flag, bool *success)
    {
        wxPrintf(wxT("Downloading: %s\n"), url.c_str());
        wxPrintf(wxT(" =>"));

        // start!
        m_lastPos = 0;
        m_pExist = flag;
        m_pSuccess = success;
        if (wxDownloadThread::Download(url, stream) != wxTHREAD_NO_ERROR)
            return false;
        return true;
    }

protected:
    volatile bool *m_pExist;
    bool *m_pSuccess;
    int m_lastPos;
};

// NB: this helper function can't be part of wxDownloadThread as the exist
//     flag must not be in the thread's memory heap
bool wxDownload(const wxString &url, const wxString &outname)
{
    // see http://www.ddj.com/dept/cpp/184403766 for more info on the use 
    // of the "volatile" keyword in this context:
    volatile bool exist = true;

    wxFileOutputStream stream(outname);
    if (!stream.IsOk())
        return false;

    wxLog::SetLogLevel(wxLOG_Info);

    wxConsoleDownloadThread *t = new wxConsoleDownloadThread();

    // here we are sure the thread still exists as it has not been started yet
    bool success = false;
    if (!t->Download(url, &stream, &exist, &success))
        return false;

    // wait until the thread has completed the download
    while (exist)
        ;

    return success;
}

bool wxAskV(const wxChar *format, va_list argPtr)
{
    wxString s;
    s.PrintfV(format, argPtr);

#ifdef __LINUX__
    char *buff = (char*)malloc(1024*sizeof(char));
    size_t n=1000;
#else
    int ch;
#endif
    do
    {
        wxPrintf(wxT("%s [y/n]\n  --> "), s.c_str());

        // read a single byte from stdin
#ifdef __LINUX__
        getline(&buff, &n, stdin);
        if (buff[0] != wxT('y') && buff[0] != wxT('n'))
#else
        ch = fgetc(stdin);
        if (ch != wxT('y') && ch != wxT('n'))
#endif
        {
            // invalid user input! ask him again a yes or no reply
            wxPrintf(wxT("\n"));
        }
        else
        {
            // valid user input - exit the loop
            break;
        }

    } while (1);

#ifdef __LINUX__
    return buff[0]==wxT('y') ? true : false;
#else
    fflush(stdin);
    return ch==wxT('y') ? true : false;
#endif
}

wxString wxAskStringV(const wxChar *format, va_list argPtr)
{
    wxString s;
    s.PrintfV(format, argPtr);

    wxPrintf(wxT("%s\n  --> "), s.c_str());

    // ask the user to input a string
#ifdef __LINUX__
    // NB: don't use the bogus fgets() or gets() functions as they
    //     leave some non-read characters in stdin which then give
    //     problems to future calls to this function!
    char *buff = (char*)malloc(1024*sizeof(char));
    size_t n=1000;
    getline(&buff, &n, stdin);

    // remove any final whitespace
    return wxString(buff).Trim();
#else
    wxChar buff[1024];
    wxFgets(buff, 1000, stdin);
    
    // fgets() won't remove the \n so do it ourselves:
    wxString ret(buff);
     if (ret.Last() == wxT('\n'))
         ret.RemoveLast();
     return ret;
#endif
}

bool wxAsk(const wxChar *format, ...)
{
    va_list argptr;
    va_start(argptr, format);
    bool reply = wxAskV(format, argptr);
    va_end(argptr);

    return reply;
}

wxString wxAskString(const wxChar *format, ...)
{
    va_list argptr;
    va_start(argptr, format);
    wxString reply = wxAskStringV(format, argptr);
    va_end(argptr);

    return reply;
}


