/*
 * pawscharpick.cpp by Andrew Craig <acraig@paqrat.com>
 *
 * Copyright (C) 2001 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.
 *
 */
#include <psconfig.h>
#include <imesh/spritecal3d.h>

#include "util/log.h"
#include "globals.h"

#include "pawscharpick.h"
#include "pawsloginwindow.h"
#include "paws/pawsbutton.h"
#include "paws/pawsmanager.h"
#include "paws/pawstextbox.h"
#include "paws/pawsobjectview.h"
#include "pawscharcreatemain.h"
#include "paws/pawsyesnobox.h"
#include "paws/pawsokbox.h"
#include "net/messages.h"
#include "iclient/isoundmngr.h"
#include "psnetmanager.h"
#include "clientcachemanager.h"
#include "pscelclient.h"
#include "psclientdr.h"

#define CHARACTER_BUTTON_0 0
#define CHARACTER_BUTTON_1 1
#define CHARACTER_BUTTON_2 2
#define CHARACTER_BUTTON_3 3

#define CHARACTER_DELETE_BUTTON 150
#define CHARACTER_ACTION_BUTTON 100

#define BACK_BUTTON             200
#define QUIT_BUTTON             250


pawsCharacterPickerWindow::pawsCharacterPickerWindow()
{
    charactersFound = 0;
    selectedCharacter = -1;
    characterCreationScreens = false;
    view = 0;
    connecting = false;
    gotStrings = false;
    lastResend = 0;
}


pawsCharacterPickerWindow::~pawsCharacterPickerWindow()
{
    if(msgHandler)
    {
        msgHandler->Unsubscribe( this, MSGTYPE_AUTHAPPROVED );
        msgHandler->Unsubscribe( this, MSGTYPE_CHAR_DELETE );
    }
}


bool pawsCharacterPickerWindow::PostSetup()
{
    msgHandler = psengine->GetMsgHandler();
    if ( !msgHandler ) return false;

    // Subscribe our message types that we are interested in. 
    msgHandler->Subscribe(this,MSGTYPE_AUTHAPPROVED);
    msgHandler->Subscribe( this, MSGTYPE_CHAR_DELETE );
        
    view = (pawsObjectView*)FindWidget("PaperDollView");
    view->Rotate(10,0.01f);
    view->EnableMouseControl(true);

    return true;
}
                          

void pawsCharacterPickerWindow::HandleMessage( MsgEntry* me )
{
    switch( me->GetType() )
    {
        // Incomming character description.  At the moment it is just the
        // character name and the factory of the mesh.
        case MSGTYPE_AUTHAPPROVED:
        {
            psAuthApprovedMessage msg(me);            

            for (int i=0; i < msg.msgNumOfChars; i++)
            {
                csString name,race,factName,traits,equipment;

                msg.GetCharacter(me,name,race,factName, traits,equipment);

                // Set the name of the character in the right button.
                char buff[100];            
                sprintf(buff, "SelectCharacter%d", charactersFound );
                pawsButton* button = (pawsButton*)FindWidget( buff );
                button->SetText( name );
                button->Show();
                sprintf(buff, "ImgCharacter%d", charactersFound );
                pawsWidget* radio = FindWidget(buff);
                radio->Show();
                
                
                char fileName[100];
                
                // Store the factory name and file name for the mesh
                sprintf( fileName, "/planeshift/models/%s/%s.cal3d", factName.GetData(),factName.GetData() );
                
                models[charactersFound].fileName = fileName;
                models[charactersFound].factName = factName;
                models[charactersFound].race = race;
                models[charactersFound].traits = traits;
                models[charactersFound].equipment = equipment;                                   
                charactersFound++;            
                                        
                SelectCharacter(0,FindWidget("SelectCharacter0"));            
            }

            // If we have all the chars we have then turn on the rest of the 
            // buttons as new character ones.                            
            // Allow player to join only after all messages have been received
            // to prevent user thinking chars have been 'lost'.
            if ( charactersFound == psengine->GetNumChars() )
            {
                pawsWidget* widget = FindWidget("login");
                if ( widget )
                    widget->Show();           
                if ( charactersFound < 4 )
                {
                    char buff[100];            
                    sprintf(buff, "SelectCharacter%d", charactersFound );
                    pawsWidget* widget = FindWidget( buff );
                    widget->Show();
                    sprintf(buff, "ImgCharacter%d", charactersFound );
                    pawsWidget* radio = FindWidget(buff);
                    radio->Show();                
                }                    

                // If there's some char created then show delete option
                pawsWidget* deleteCharBut = FindWidget("delete");
                if (deleteCharBut)
                    deleteCharBut->Show();
            }
            return;
        }
        case MSGTYPE_CHAR_DELETE:
        {
            // Emulate back click
            OnButtonPressed(1,0,FindWidget(BACK_BUTTON));
            break;
        }
    }
    
}

bool pawsCharacterPickerWindow::OnButtonPressed( int mouseButton, int keyModifer, pawsWidget* widget )
{
    if(!widget)
        return false;

    switch ( widget->GetID() )
    {
        case CHARACTER_DELETE_BUTTON:
        {
            char name[100];
            sprintf( name, "SelectCharacter%d", selectedCharacter );
            csString confirm;
            confirm.Format( "Are you sure you want to delete %s?", 
                ((pawsButton*)FindWidget(name))->GetText() );
            PawsManager::GetSingleton().CreateYesNoBox( confirm, this );

            return true;
        }

        case BACK_BUTTON:
        {
            ReturnToLoginWindow();
            return true;
        }

        case CONFIRM_YES:
        {
            //Delete the selected character
            char name[100];
            sprintf( name, "SelectCharacter%d", selectedCharacter );

            // Get Full name.
            psString charFullName( ((pawsButton*)FindWidget(name))->GetText() );
            psString charFirstName;
            charFullName.GetWord( 0, charFirstName );

            psCharDeleteMessage out( charFirstName, 0 );
            msgHandler->SendMessage( out.msg );

            return true;
        }

        case CONFIRM_NO:
        {
            PawsManager::GetSingleton().SetModalWidget(NULL);
            widget->GetParent()->Hide();
            return true;
        }

        case OK_BUTTON:
        {
            ReturnToLoginWindow();
            return true;
        }

        case CHARACTER_BUTTON_0:
        case CHARACTER_BUTTON_1:
        case CHARACTER_BUTTON_2:
        case CHARACTER_BUTTON_3:
        {
            if(!connecting)
                SelectCharacter(widget->GetID(),widget);
            break;    
        }
        
        case CHARACTER_ACTION_BUTTON:
        {
            // if we have a character then we play as that one.
            if ( selectedCharacter != -1 && !connecting )
            {
                // Disable the button so that we don't send 2 picker message
                connecting = true;

                char name[100];
                sprintf( name, "SelectCharacter%d", selectedCharacter );
                
                // Send the name of the character to the server. 
                csString charname( ((pawsButton*)FindWidget(name))->GetText() );
                                
                psCharacterPickerMessage out( charname );
                msgHandler->SendMessage( out.msg );
            }
            
            return true;
        }
        
        case QUIT_BUTTON:
        {
            psengine->QuitClient();
            return true;
        }
       
    }
    return false;
}

void pawsCharacterPickerWindow::ReturnToLoginWindow()
{
    //    psengine->GetNetManager()->SendDisconnect(false);
    //    psengine->GetNetManager()->Disconnect();
    psengine->Disconnect(false); // This isn't the final disconnect

    psengine->GetCelClient()->GetClientDR()->ResetMsgStrings(); // Remove the message to prevent big CRASH in the client

    pawsLoginWindow* loginWin = (pawsLoginWindow*)PawsManager::GetSingleton().FindWidget("LoginWindow");
    if ( !loginWin )
    {
        PawsManager::GetSingleton().LoadWidget("data/gui/loginwindow.xml");
        loginWin = (pawsLoginWindow*)PawsManager::GetSingleton().FindWidget("LoginWindow");
    }

    loginWin->Show();
    this->Hide();
    this->DeleteYourself();
    return;
}


void pawsCharacterPickerWindow::SetupCharacterCreationScreens()
{
    if (!characterCreationScreens )
    {
        static char* screenFiles[] = 
        {
           "data/gui/charcreate.xml",
           "data/gui/birth.xml",
           "data/gui/parents.xml",
           "data/gui/childhood.xml",
           "data/gui/lifeevents.xml",           
           "data/gui/paths.xml",
           "data/gui/summary.xml",
           0
        };
    
        int i = 0;
        while ( screenFiles[i] != 0 )
        {
            if ( !PawsManager::GetSingleton().LoadWidget( screenFiles[i] ) )
            {
                Error2("FAILED to load screen: %s\n", screenFiles[i] );
                return;
            }
            i++;
        }
                   
        characterCreationScreens = true;            
    }
        
    pawsCreationMain* widget = (pawsCreationMain*)PawsManager::GetSingleton().FindWidget("CharCreateMain");       
    
    psengine->GetCharManager()->GetCreation()->ClearChoices();    
    if ( widget )
    {
        widget->Reset();          
        widget->Show();
    }        
        
    Hide();     
    
}

void pawsCharacterPickerWindow::Show()
{
    pawsWidget* credits = PawsManager::GetSingleton().FindWidget("CreditsWindow");
    if(credits)
        credits->Hide();

    // Sync the gotStrings with psClientDR
    gotStrings = psengine->GetCelClient()->GetClientDR()->GotStrings();
    if(gotStrings)
        ReceivedStrings();
    else
        lastResend = csGetTicks(); // Resend 5 secs from now

    // If there are no characters to find then turn on one of the new account
    // buttons        
    if ( psengine->GetNumChars() == 0 )
    {
        pawsWidget* widget = FindWidget("SelectCharacter0");
        if ( widget ) widget->Show();
    }        
        
    // Play some music
    if(psengine->GetSoundStatus())
    {
        psengine->GetSoundManager()->OverrideBGSong("mainmenu");
    }
    PawsManager::GetSingleton().SetCurrentFocusedWidget(this);

    pawsWidget::Show();
}

void pawsCharacterPickerWindow::SelectCharacter(int character)
{        
    if(!gotStrings)
        return;

    pawsWidget* wdg;

    for (int i = 0;i < 4; i++)
    {
        csString name;
        name = "ImgCharacter";
        name += i;
        wdg = FindWidget(name);
        if (!wdg)
            return;

        if (character == i && charactersFound != 0 )
            wdg->SetBackground("radioon2");
        else
            wdg->SetBackground("radiooff2");
    }
    view->Show();
    if ( charactersFound == 0 )
        return;
        
    pawsButton* loginWidget = (pawsButton*)FindWidget("login");            
    char name[100];
    sprintf( name, "SelectCharacter%d", character );
    pawsWidget* box = FindWidget(name);    
    if ( box )    
        selectedCharacter = box->GetID();
    else 
        selectedCharacter = 0;        
    
    if(gotStrings)
        loginWidget->SetText( PawsManager::GetSingleton().Translate("Join") );
            
    // If the button selected has an empty character then button will
    // be for creating a new character
    if ( selectedCharacter >= charactersFound  )
    {
        return;
    }
    else
    {
        // Show the model for the selected character.
        view->Show();
        FactoryIndexEntry* entry = psengine->GetCacheManager()->GetFactoryEntry(models[selectedCharacter].fileName);
        if (!entry)
        {
            psengine->FatalError("The server sent an invalid model filename, please run the updater\n");
            printf("Model sent: %s",models[selectedCharacter].fileName.GetData());
            return;
        }

        if (entry->factname != "")
            view->View( entry->factname, entry->filename );
        else
            view->View(entry->factory);
                
        iMeshWrapper * mesh = view->GetObject();
        if (!mesh)
        {
            PawsManager::GetSingleton().CreateWarningBox("Couldn't find mesh! Please run the updater");
            return;
        }

        csRef<iSpriteCal3DState> spstate =
            SCF_QUERY_INTERFACE(mesh->GetMeshObject(),
                                        iSpriteCal3DState);
        if (spstate)
        {
            // Setup cal3d to select random 0 velocity anims
            spstate->SetVelocity(0.0,&psengine->GetRandomGen());
            csString traits(models[selectedCharacter].traits);
            csString equipment( models[selectedCharacter].equipment );
            psengine->BuildAppearance( mesh, traits );     
            
            csPDelArray<Trait> dummy;
            psengine->BuildEquipment(mesh, equipment, dummy);               
        }
    }
}



void pawsCharacterPickerWindow::SelectCharacter(int character, pawsWidget* widget)
{
    if(!gotStrings)
        return;

    pawsWidget* wdg;

    for (int i = 0;i < 4; i++)
    {
        csString name;
        name = "ImgCharacter";
        name += i;
        wdg = FindWidget(name);
        if (!wdg)
            return;

        if (character == i)
            wdg->SetBackground("radioon2");
        else
            wdg->SetBackground("radiooff2");
    }

    pawsButton* loginWidget = (pawsButton*)FindWidget("login");

    selectedCharacter = widget->GetID();                                    
    loginWidget->SetText( PawsManager::GetSingleton().Translate("Join") );
                
    // If the button selected has an empty character then button will
    // be for creating a new character
    if ( widget->GetID() >= charactersFound  )
    {            
        SetupCharacterCreationScreens();
        view->Hide();
    }
    else
    {
        // Show the model for the selected character.
        view->Show();
        FactoryIndexEntry* entry = psengine->GetCacheManager()->GetFactoryEntry(models[selectedCharacter].fileName);
        if (!entry)
        {
            psengine->FatalError("The server sent an invalid model filename, please run the updater\n");
            return;
        }

        if (entry->factname != "")
            view->View( entry->factname, entry->filename );
        else
            view->View(entry->factory);
                
        iMeshWrapper * mesh = view->GetObject();
        if (!mesh)
        {
            PawsManager::GetSingleton().CreateWarningBox("Couldn't find mesh! Please run the updater");
            return;
        }

        csRef<iSpriteCal3DState> spstate =
            SCF_QUERY_INTERFACE(mesh->GetMeshObject(),
                                        iSpriteCal3DState);
        if (spstate)
        {
            // Setup cal3d to select random 0 velocity anims
            spstate->SetVelocity(0.0,&psengine->GetRandomGen());
            csString traits(models[selectedCharacter].traits);
            csString equipment( models[selectedCharacter].equipment );
            psengine->BuildAppearance( mesh, traits );     
            csPDelArray<Trait> dummy;
            psengine->BuildEquipment( mesh, equipment, dummy );               
        }
    }
}

void pawsCharacterPickerWindow::Draw()
{
    pawsWidget::Draw();
}

void pawsCharacterPickerWindow::ReceivedStrings()
{
    gotStrings = true;

    pawsTextBox* label = (pawsTextBox*)FindWidget("wait_label");
    if(label)
        label->Hide();

    if(charactersFound > 0 && charactersFound == psengine->GetNumChars())
    {
        SelectCharacter(0);
    }
}
