/***************************************************************************
 *   Copyright (C) 2004 by yunfan                                          *
 *   yunfan_zg@163.com                                                     *
 *                                                                         *
 *   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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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 "evauser.h"
#include "evausersetting.h"
#include "evaqtutil.h"
#include "evautil.h"
#include <string.h>
#include <qevent.h>

std::string EvaUser::qunName = "Qun List";
std::string EvaUser::anonymousName = "Anonymous";
std::string EvaUser::blackName = "Black List";

EvaUser::EvaUser(const int id, const std::string &password)
{	
	char *tmp = (char *)malloc(password.length() * sizeof(char));
        memcpy(tmp, password.c_str(), password.length());
	qqNum = id;
	md5Password = new char[16];
	memcpy(md5Password, EvaUtil::doMd5Md5(tmp, password.length()), 16);

	timeOnline = 0;
	level = 0;
	hoursToLevelUp = 0;

	mSignature = "";
	mSignatureModifyTime = 0;

	status = Eva_Offline;
	groupNames.clear();
	setting = new EvaUserSetting(id);
	setting->loadSettings();
	isBuddyListLoaded = false;
	isQunListLoaded = false;

	mLoginManager = new EvaLoginProcess();
}

EvaUser::EvaUser(const int id, const char *md5Password)
{
	qqNum = id;
	
	this->md5Password = new char[16];
	memcpy(this->md5Password, md5Password, 16);
	
	timeOnline = 0;
	level = 0;
	hoursToLevelUp = 0;

	mSignature = "";
	mSignatureModifyTime = 0;
	
	status = Eva_Offline;
	groupNames.clear();
	setting = new EvaUserSetting(id);
	mLoginManager = new EvaLoginProcess();
}

EvaUser::~EvaUser()
{
	delete md5Password;
	delete setting;
}

char EvaUser::getStatusCode(const UserStatus status) 
{
	char statusCode;
	switch(status){
	case Eva_Online:
		statusCode = QQ_FRIEND_STATUS_ONLINE;
		break;
	case Eva_Offline:
		statusCode = QQ_FRIEND_STATUS_OFFLINE;
		break;
	case Eva_Invisible:
		statusCode = QQ_FRIEND_STATUS_INVISIBLE;
		break;
	case Eva_Leave:
		statusCode = QQ_FRIEND_STATUS_LEAVE;
		break;
	default:
		statusCode = QQ_FRIEND_STATUS_OFFLINE;
	}
	return statusCode;
}

const bool EvaUser::newGroup( const std::string & name )
{
	if(name == "") return false;
	groupNames.push_back(name);
	return true;
}

void EvaUser::clearGroupNames()
{
	std::string buddy = groupNameAtIndex(0); 
	groupNames.clear();
	groupNames.push_back(buddy);	
}

void EvaUser::removeGroupName(const int index)
{
	if(index == 0 ) return; // the first group name cannot be removed
	if((uint)index >= groupNames.size()) return; 
	std::list<std::string>::iterator iter;
	iter = groupNames.begin();
	for(int i=0; i<index; i++)
		iter++;
	groupNames.erase(iter);
}

const int EvaUser::getGroupIndexOf(const std::string &name)
{
	std::list<std::string>::iterator iter;
	int i=0;	
	for(iter=groupNames.begin(); iter != groupNames.end(); ++iter){
		if(name== *iter) break;
		++i;
	}
	if((uint)i>= groupNames.size()) 
		return -1;
	else 
		return i;	
}

void EvaUser::updateGroupName(const std::string &newName, const int index)
{
	if(index == 0 ) return; // the first group name cannot be removed
	if((uint)index >= groupNames.size()) return; 
	std::list<std::string>::iterator iter;
	iter = groupNames.begin();
	int i;
	for(i=0; i<index; i++){
		iter++;
	}
	groupNames.insert(iter, newName);
	groupNames.erase(iter);
}

const std::string EvaUser::groupNameAtIndex( const int index )
{
	if(index == anonymousIndex) return anonymousName;
	if(index == blackIndex) return blackName;
	
	if((uint)index>= groupNames.size()) return "My Buddy";
	
	std::list<std::string>::iterator iter;
	int i=0;	
	for(iter=groupNames.begin(); iter != groupNames.end(); ++iter){
		if(i==index) break;
		++i;
	}
	return *iter;
}

const bool EvaUser::loadGroupedBuddyList()
{
	if(setting->loadBuddyList(this)){
		isBuddyListLoaded = true;
	}else{
		isBuddyListLoaded = false;
	}
	return isBuddyListLoaded;
}

const bool EvaUser::saveGroupedBuddyList()
{
	return setting->saveBuddyList(this, groupNames, details, myFriends, mExtraInfo, mSignature, mSignatureModifyTime);
}


void EvaUser::customEvent( QCustomEvent * e )
{
	if(e->type() == EvaLoadGroupedUsersEvent){
		EvaBuddyListEvent *ge = (EvaBuddyListEvent *)e;
		details = ge->getMyInfo();
		groupNames = ge->getGroupNames();
		myFriends = ge->getMyFriendList();
		mExtraInfo = ge->getExtraInfo();
		mSignature = ge->getSignature();
		mSignatureModifyTime = ge->getSignatureTime();
		emit loadGroupedBuddiesReady();
	}
	if(e->type() == EvaLoadQunUsersEvent){
		EvaQunListEvent *gl = (EvaQunListEvent *)e;
		qunList = gl->getQunList();
		emit loadQunListReady();
	}
}

const bool EvaUser::loadQunList( )
{
	if(setting->loadQunList(this)){
		isQunListLoaded = true;
	}else{
		isQunListLoaded = false;
	}
	return isQunListLoaded;
}

const bool EvaUser::saveQunList( )
{
	return setting->saveQunList(this, qunList);
}


/** ==========================================================================  */

EvaLoginProcess::EvaLoginProcess( )
{
	initFlags();
}

const int EvaLoginProcess::nextNumOperation( )
{
	int num = 0;
	switch(mNextStep){
	case 0:
	case 1:
		num = 1;
		break;
	case 2:
		num = 4;
		break;
	}
	return num;
}

const short EvaLoginProcess::nextStep( )
{
	short cmd = -1;
	switch(mNextStep){
	case 0:
		cmd = mCommands[0];
		break;
	case 1:
		cmd = mCommands[1];
		break;
	case 2:{
		if(mFlags[mCommands[2]]){
			if(mFlags[mCommands[3]]){
				if(mFlags[mCommands[4]]){
					if(!mFlags[mCommands[5]])
						cmd = mCommands[5];
				}else
					cmd = mCommands[4];
			}else
				cmd = mCommands[3];
		}else
			cmd = mCommands[2];
		cmd = mCommands[2 + mCurrentStepTwo];
		mCurrentStepTwo = (mCurrentStepTwo+1) % 4;
		}
		break;
	}
	return cmd;
}

void EvaLoginProcess::clearCommandFlag( const short cmd )
{
	switch(cmd){
	case QQ_CMD_REQUEST_LOGIN_TOKEN:
		mFlags[cmd] = false;
		mNextStep = 0;
	case QQ_CMD_LOGIN:
		mFlags[cmd] = false;
		mNextStep = 1;
		break;
	case QQ_CMD_REQUEST_KEY:
	case QQ_CMD_GET_USER_INFO:
	case QQ_CMD_CHANGE_STATUS:
	case QQ_CMD_GET_FRIEND_LIST:
		mFlags[cmd] = false;
		mNextStep = 2;
	}
}

void EvaLoginProcess::finishedCommand( const short cmd )
{
	switch(cmd){
	case QQ_CMD_REQUEST_LOGIN_TOKEN:
	case QQ_CMD_LOGIN:
		mFlags[cmd] = true;
		mNextStep++;
		break;
	case QQ_CMD_REQUEST_KEY:
	case QQ_CMD_GET_USER_INFO:
	case QQ_CMD_CHANGE_STATUS:
	case QQ_CMD_GET_FRIEND_LIST:
		mFlags[cmd] = true;
		if(mCurrentStepTwo==4) mNextStep++;
	}
	if(isReady())
		emit processReady();
}

void EvaLoginProcess::initFlags( )
{
	mNextStep = 0;
	mCurrentStepTwo = 0;
	mCommands[0] = QQ_CMD_REQUEST_LOGIN_TOKEN;
	mCommands[1] = QQ_CMD_LOGIN;
	mCommands[2] = QQ_CMD_REQUEST_KEY;  // note this is only for key type 04
	mCommands[3] = QQ_CMD_GET_USER_INFO;
	mCommands[4] = QQ_CMD_CHANGE_STATUS;
	mCommands[5] = QQ_CMD_GET_FRIEND_LIST;
	
	mFlags[mCommands[0]] = false;
	mFlags[mCommands[1]] = false;
	mFlags[mCommands[2]] = false;
	mFlags[mCommands[3]] = false;
	mFlags[mCommands[4]] = false;
	mFlags[mCommands[5]] = false;
}

void EvaLoginProcess::reset( )
{
	initFlags();
}

const bool EvaLoginProcess::isReady( )
{
	return (mFlags[QQ_CMD_REQUEST_LOGIN_TOKEN] && mFlags[QQ_CMD_LOGIN] && 
		mFlags[QQ_CMD_REQUEST_KEY] && mFlags[QQ_CMD_GET_USER_INFO] && 
		mFlags[QQ_CMD_CHANGE_STATUS] && mFlags[QQ_CMD_GET_FRIEND_LIST]);
}

const bool EvaLoginProcess::isCommandFinished(const short cmd)
{
	return mFlags[cmd];
}



