/*
* pawscontrolwindow.cpp - Author: Alexander Wiseman
*
* Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
*
*
* 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 (version 2 of the License)
* 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.
*
*/
//////////////////////////////////////////////////////////////////////

// STANDARD INCLUDE
#include <psconfig.h>
#include "globals.h"

// COMMON/NET INCLUDES
#include "net/messages.h"
#include "net/msghandler.h"
#include "net/cmdhandler.h"
#include "util/strutil.h"

#include "pscelclient.h"

// PAWS INCLUDES
#include "pawspetitionwindow.h"
#include "pawspetitiongmwindow.h"
#include "paws/pawsmainwidget.h"

#define QUIT_BUTTON            1000
#define    ASSIGN_BUTTON       2
#define ESCALATE_BUTTON     3
#define DESCALATE_BUTTON    4
#define CLOSE_BUTTON        5
#define CANCEL_BUTTON       6
#define ADMIN_BUTTON        7

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

pawsPetitionGMWindow::pawsPetitionGMWindow() 
: psCmdBase( NULL,NULL,  PawsManager::GetSingleton().GetObjectRegistry() )
{
}

pawsPetitionGMWindow::~pawsPetitionGMWindow()
{
    msgqueue->Unsubscribe(this, MSGTYPE_PETITION);
}

bool pawsPetitionGMWindow::PostSetup()
{
    // Setup this widget to receive messages and commands
    if ( !psCmdBase::Setup( psengine->GetMsgHandler(), psengine->GetCmdHandler()) )
        return false;

    // Subscribe to certain types of messages (those we want to handle)
    msgqueue->Subscribe(this, MSGTYPE_PETITION);

    // Grab the pointer to the petition listbox:
    petitionList = (pawsListBox*)FindWidget("PetitionList");

    petText = (pawsMessageTextBox*)FindWidget("PetitionText");

    hasPetInterest = false;

    // If player is GM, give him the /petition_manage command
    if ( psengine->GetCelClient()->GetMainPlayer()->GetType() > 20 )
        cmdsource->Subscribe("/petition_manage", this);

    return true;
}

//////////////////////////////////////////////////////////////////////
// Command and Message Handling
//////////////////////////////////////////////////////////////////////

const char* pawsPetitionGMWindow::HandleCommand( const char* cmd )
{
    char* buff = csStrNew(cmd);

    // Check which command was invoked:
    if ( !strncmp(buff+1, "petition_manage", 13))
    {
        hasPetInterest = true;
        
        // First, display this window to the user
        Show();
    
        // Query the server for messages:
        QueryServer();
    }

    return NULL;
}

void pawsPetitionGMWindow::HandleMessage ( MsgEntry* me )
{
    //printf("Incomming Petition GM Petition Message\n");
    // Get the petition message data from the server
    psPetitionMessage message(me);

    if (!message.isGM)
    {
        //printf("Bailing out because of message.isGM");
        return;
    }        

    if (message.msgType == PETITION_DIRTY && psengine->GetCelClient()->GetMainPlayer()->GetType() > 20)
    {
        if (hasPetInterest)
        {
            //printf("Looking for pet interest and bailing out\n");
            QueryServer();
        }            
        return;
    }
    
    // if the server gave us a list of petitions, then use it
//    if (message.petitions.Length() > 0)
    petitionMessage = message;

    // Check if server reported errors on the query
    if (!message.success)
    {
        printf("Message was not a success\n");
        psSystemMessage error(0,MSG_INFO,message.error);
        msgqueue->Publish(error.msg);

        petCount = 0;
        petitionList->Clear();
        petitionList->NewRow(0);
        SetText(0, 1, PawsManager::GetSingleton().Translate("No Petitions"));
        return;
    }

    // Check no petitions:
    if (message.petitions.Length() == 0)
    {
        //printf("No petitions in list\n");
        petCount = 0;
        petitionList->Clear();
        petitionList->NewRow(0);
        SetText(0, 1, PawsManager::GetSingleton().Translate("No Petitions"));
        return;
    }

    // Check its type (list, confirm, or assign):
    if (message.msgType == PETITION_CANCEL || message.msgType == PETITION_CLOSE)
    {
        // Check if server reported errors on the query
        if (!message.success)
        {
            printf("!message.succss\n");
            psSystemMessage error(0,MSG_INFO,message.error);
            msgqueue->Publish(error.msg);
            return;
        }

        // Change the status of the position we wanted to cancel:
        if (currentRow < 0)
        {
            // This should NEVER happen (it means the server gave a bogus message)
            Error1("PetitionGMWindow reports invalid currentRow!");
            printf("Invalid currentRow\n");
            return;
        }

        // Remove the item and refresh the list:
//        petitionMessage.petitions.DeleteIndex(currentRow);
        //printf("Adding peitions\n");
        AddPetitions(petitionMessage.petitions);

        csString report;
        csString translation1 = PawsManager::GetSingleton().Translate("The selected petition was %s");
        csString translation2 = PawsManager::GetSingleton().Translate(message.msgType == PETITION_CANCEL ? "cancelled.":"closed.");
        report.Format(translation1.GetData(), translation2.GetData());
        psSystemMessage confirm(0,MSG_INFO,report.GetData());
        msgqueue->Publish(confirm.msg);

        
        return;
    }

    if (message.msgType == PETITION_ASSIGN)
    {
        // Check if server reported errors on the query
        if (!message.success)
        {
            printf("Assign fail\n");
            psSystemMessage error(0,MSG_INFO,message.error);
            msgqueue->Publish(error.msg);
            return;
        }

        // Change the status of the position we wanted to assign:
        if (currentRow < 0)
        {
            printf("Bad row\n");
            // This should NEVER happen (it means the server gave a bogus message)
            Error1("PetitionGMWindow reports invalid currentRow!");
            return;
        }

        // Change the status of the item in the list box:
//        petitionMessage.petitions.Get(currentRow).status = "In Progress";
        AddPetitions(petitionMessage.petitions);

        psSystemMessage confirm(0,MSG_INFO,PawsManager::GetSingleton().Translate("You have been assigned to the selected petition."));
        msgqueue->Publish(confirm.msg);

        return;
    }

    if (message.msgType == PETITION_ESCALATE)
    {
        //printf("Escalate\n");
        // Check if server reported errors on the query
        if (!message.success)
        {            
            psSystemMessage error(0,MSG_INFO,message.error);
            msgqueue->Publish(error.msg);
            return;
        }

        // Change the status of the position we wanted to assign:
        if (currentRow < 0)
        {
            // This should NEVER happen (it means the server gave a bogus message)
            Error1("PetitionGMWindow reports invalid currentRow!");
            return;
        }

        // Change the status of the item in the list box:
//        petitionMessage.petitions.Get(currentRow).escalation += 1;
//        petitionMessage.petitions.Get(currentRow).status = "Open";
        AddPetitions(petitionMessage.petitions);

        psSystemMessage confirm(0,MSG_INFO,PawsManager::GetSingleton().Translate("The selected petition has been escalated."));
        msgqueue->Publish(confirm.msg);

        return;
    }
    if (message.msgType == PETITION_DESCALATE)
    {
        //printf("Descalate\n");
        // Check if server reported errors on the query
        if (!message.success)
        {            
            psSystemMessage error(0,MSG_INFO,message.error);
            msgqueue->Publish(error.msg);
            return;
        }

        // Change the status of the position we wanted to assign:
        if (currentRow < 0)
        {
            // This should NEVER happen (it means the server gave a bogus message)
            Error1("PetitionGMWindow reports invalid currentRow!");
            return;
        }

        // Change the status of the item in the list box:
        AddPetitions(petitionMessage.petitions);

        psSystemMessage confirm(0,MSG_INFO,PawsManager::GetSingleton().Translate("The selected petition has been descalated."));
        msgqueue->Publish(confirm.msg);

        return;
    }

    // Update the listbox:
    printf("Adding petitions\n");
    int tempCount = petCount;
    AddPetitions(message.petitions);

    //alert GM that there are petitons waiting
    if (petCount > tempCount)
    {
        psSystemMessage alert(0,MSG_INFO,PawsManager::GetSingleton().Translate("Petitons are waiting."));
        msgqueue->Publish(alert.msg);
    }
}

bool pawsPetitionGMWindow::OnButtonPressed( int mouseButton, int keyModifier, pawsWidget* widget )
{  
    // We know that the calling widget is a button.
    int button = widget->GetID();

    switch( button )
    {
        case QUIT_BUTTON:
        {
            // Hide our petition window
            petitionList->Clear();
            Hide();
            break;
        }

        case CANCEL_BUTTON:
        {
            if (petCount > 0)
            {
                // Get the currently selected row:
                int sel = petitionList->GetSelection();
                if (sel < 0)
                {
                    psSystemMessage error(0,MSG_INFO,PawsManager::GetSingleton().Translate("You must select a petition from the list in order to cancel it."));
                    msgqueue->Publish(error.msg);
                    return true;
                }

                if (csString("In Progress") == ((pawsTextBox*)(petitionList->GetSelected()->GetColumn(PGMCOL_STATUS)))->GetText())
                {

                    currentRow = sel;

                    // Send a message to the server requesting cancel
                    psPetitionRequestMessage queryMsg(true, "cancel", petitionMessage.petitions.Get(currentRow).id);
                    msgqueue->SendMessage(queryMsg.msg);
                }
                else
                {
                    psSystemMessage error(0,MSG_INFO,PawsManager::GetSingleton().Translate("You must be assigned to a petition in order to cancel it."));
                    msgqueue->Publish(error.msg);
                }
            }
            break;
        }

        case ASSIGN_BUTTON:
        {
            if (petCount > 0)
            {
                // Get the currently selected row:
                int sel = petitionList->GetSelection();
                if (sel < 0)
                {
                    psSystemMessage error(0,MSG_INFO,PawsManager::GetSingleton().Translate("You must select a petition from the list in order to assign yourself."));
                    msgqueue->Publish(error.msg);
                    return true;
                }
        
                if (csString("Open") == ((pawsTextBox*)(petitionList->GetSelected()->GetColumn(PGMCOL_STATUS)))->GetText())
                {
                    currentRow = sel;
            
                    // Send a message to the server requesting assignment:
                    psPetitionRequestMessage queryMsg(true, "assign", petitionMessage.petitions.Get(currentRow).id);
                    msgqueue->SendMessage(queryMsg.msg);
                }
                else
                {
                    psSystemMessage error(0,MSG_INFO,PawsManager::GetSingleton().Translate("The selected petition isn't Open."));
                    msgqueue->Publish(error.msg);
                }
            }
            break;
        }

        case CLOSE_BUTTON:
        {
            if (petCount > 0)
            {
                // Get the currently selected row:
                int sel = petitionList->GetSelection();
                if (sel < 0)
                {
                    psSystemMessage error(0,MSG_INFO,PawsManager::GetSingleton().Translate("You must select a petition from the list in order to close it."));
                    msgqueue->Publish(error.msg);
                    return true;
                }
            
                if (csString("In Progress") == ((pawsTextBox*)(petitionList->GetSelected()->GetColumn(PGMCOL_STATUS)))->GetText())
                {
                    currentRow = sel;

                    pawsStringPromptWindow::Create(PawsManager::GetSingleton().Translate("Describe the petition and how you've helped"), "", 
                                                   true, 400, 60, this, "CloseDesc");
                }
                else
                {
                    psSystemMessage error(0,MSG_INFO,PawsManager::GetSingleton().Translate("You must be assigned to a petition in order to close it."));
                    msgqueue->Publish(error.msg);
                }
            }
            break;
        }

        case ESCALATE_BUTTON:
        {
            if (petCount > 0)
            {
                // Get the currently selected row:
                int sel = petitionList->GetSelection();
                if (sel < 0)
                {
                    psSystemMessage error(0,MSG_INFO,PawsManager::GetSingleton().Translate("You must select a petition from the list in order to escalate it."));
                    msgqueue->Publish(error.msg);
                    return true;
                }

                if (psengine->GetCelClient()->GetMainPlayer()->GetType() + 1 >= atof(((pawsTextBox*)(petitionList->GetSelected()->GetColumn(PGMCOL_LVL)))->GetText()))
                {
                    currentRow = sel;
        
                    // Send a message to the server requesting assignment:
                    psPetitionRequestMessage queryMsg(true, "escalate", petitionMessage.petitions.Get(currentRow).id);
                    msgqueue->SendMessage(queryMsg.msg);
                }
            }
            break;
        }
    
        case DESCALATE_BUTTON:
        {
            if (petCount > 0)
            {
                // Get the currently selected row:
                int sel = petitionList->GetSelection();
                if (sel < 0)
                {
                    psSystemMessage error(0,MSG_INFO,PawsManager::GetSingleton().Translate("You must select a petition from the list in order to descalate it."));
                    msgqueue->Publish(error.msg);
                    return true;
                }

                if (psengine->GetCelClient()->GetMainPlayer()->GetType() + 1 >= atof(((pawsTextBox*)(petitionList->GetSelected()->GetColumn(PGMCOL_LVL)))->GetText()))
                {
                    currentRow = sel;
        
                    // Send a message to the server requesting assignment:
                    psPetitionRequestMessage queryMsg(true, "descalate", petitionMessage.petitions.Get(currentRow).id);
                    msgqueue->SendMessage(queryMsg.msg);
                }
            }
            break;
        }

        case ADMIN_BUTTON:
        {
            // store the target petitioner data
            if (petCount > 0)
            {
                // Get the currently selected row:
                int sel = petitionList->GetSelection();
                if (sel < 0)
                    psengine->SetTargetPetitioner("None");
                else
                {
                    if (csString("In Progress") == ((pawsTextBox*)(petitionList->GetSelected()->GetColumn(PGMCOL_STATUS)))->GetText())
                        psengine->SetTargetPetitioner(((pawsTextBox*)(petitionList->GetSelected()->GetColumn(PGMCOL_PLAYER)))->GetText());
                    else
                        psengine->SetTargetPetitioner("None");
                }
            }
            else
                psengine->SetTargetPetitioner("None");
            
            // load the gm gui so that the gm can access functions to aid the pet
            const char* errorMessage = cmdsource->Publish( "/show_gm" );
            if ( errorMessage )
            {
                psSystemMessage error(0,MSG_INFO,errorMessage);
                msgqueue->Publish(error.msg);
            }
        }
    }

    return true;
}

void pawsPetitionGMWindow::OnStringEntered(const char *name,int param,const char *value)
{
    if (value && strlen(value))
        CloseCurrPetition(value);
}

//////////////////////////////////////////////////////////////////////
// Helper Functions
//////////////////////////////////////////////////////////////////////

void pawsPetitionGMWindow::CloseCurrPetition(const char *desc)
{
    // Send a message to the server requesting assignment:
    psPetitionRequestMessage queryMsg(true, "close", petitionMessage.petitions.Get(currentRow).id, desc);
    msgqueue->SendMessage(queryMsg.msg);
}

void pawsPetitionGMWindow::QueryServer()
{
    // Construct the special petition request message to ask the server for info
    psPetitionRequestMessage queryMsg(true, "query");
    msgqueue->SendMessage(queryMsg.msg);
}

void pawsPetitionGMWindow::SetText(size_t rowNum, int colNum, const char* fmt, ...)
{
    pawsListBoxRow *row = petitionList->GetRow(rowNum);
    if (!row)
        return;

    pawsTextBox *curCol = (pawsTextBox*)row->GetColumn(colNum);
    if (!curCol)
        return;

    char text[1024];
    va_list args;

    va_start(args, fmt);
    cs_vsnprintf(text,sizeof(text),fmt,args);
    va_end(args);

    // Check text overflow:
    csString overflow = text;
    if (overflow.Length() > MAX_GMPETITION_LENGTH)
    {
        overflow.Truncate(MAX_GMPETITION_LENGTH);
        overflow << "...";
    }

    curCol->SetText(overflow.GetData());
}


void pawsPetitionGMWindow::AddPetitions(csArray<psPetitionInfo> &petitions)
{
    // figure out the selected petition
    
    
    if (petitionList->GetRowCount() <= 0)
        petitionList->Select(NULL);

    int selRow = petitionList->GetSelection();
    if (selRow != -1)
    {
        csString escalation = petitionList->GetTextCellValue(selRow, PGMCOL_LVL);
        if (escalation.GetData() != NULL)
            selectedPet.escalation = atoi(escalation.GetData());
        else
            selectedPet.escalation = -1;
        selectedPet.player =          petitionList->GetTextCellValue(selRow, PGMCOL_PLAYER);
        selectedPet.status =          petitionList->GetTextCellValue(selRow, PGMCOL_STATUS);
        selectedPet.created =         petitionList->GetTextCellValue(selRow, PGMCOL_CREATED);
        selectedPet.petition =        petitionList->GetTextCellValue(selRow, PGMCOL_PETITION);
    }
    else
    {
        selectedPet.escalation = -1;
    }
    petitionList->Select(NULL);
    
    // Clear the list box and add the user's petitions
    petitionList->Clear();
    psPetitionInfo info;
    petCount = 0;
    for (size_t i = 0; i < petitions.Length(); i++)
    {
        info = petitions.Get(i);
        petCount++;
                    
        // Set the data for this row:
        petitionList->NewRow(i);
        SetText(i, PGMCOL_LVL, "%d", info.escalation);
        SetText(i, PGMCOL_PLAYER, "%s", info.player.GetData());
        SetText(i, PGMCOL_STATUS, "%s", info.status.GetData());
        SetText(i, PGMCOL_CREATED, "%s", info.created.GetData());
        SetText(i, PGMCOL_PETITION, "%s", info.petition.GetData());

        // reselect the petition        
        if (selectedPet.escalation != -1)
        {
            if (selectedPet.created == info.created
             && selectedPet.player == info.player)
            {
                petitionList->Select(petitionList->GetRow(i));
            }
        }
    }
    // make absolutely sure that there are petitions
    if (petCount <= 0)
    {
        petitionList->NewRow(0);
        SetText(0, 1, PawsManager::GetSingleton().Translate("No Petitions"));
    }
}


void pawsPetitionGMWindow::OnListAction( pawsListBox* selected, int status )
{
    if (status == LISTBOX_HIGHLIGHTED)
    {
        size_t sel = petitionList->GetSelection();
        if (sel >= petitionMessage.petitions.Length())
            return;
        petText->Clear();
        petText->AddMessage(petitionMessage.petitions.Get(sel).petition);
    }
}

