/***************************************************************************
 *   Copyright (C) 2008 by SK Communications.                              *
 *   http://kldp.net/projects/nateon/                                      *
 *                                                                         *
 *   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 3 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 "sqlitedb.h"

SQLiteDB::SQLiteDB(QObject *parent, const char *name)
	: QObject(parent, name), db(0), nChatMID(0), nMemoMID(0)
{
}


SQLiteDB::~SQLiteDB()
{
}

int SQLiteDB::callback(void * NotUsed, int argc, char ** argv, char ** azColName)
{
	int i;
	for(i=0; i<argc; i++)
	{
		printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
	}
	printf("\n");
	Q_UNUSED( NotUsed );
	return 0;
}

void SQLiteDB::execOne( const QString &sFile, const QString &sCommand )
{
	char *zErrMsg = 0;
	int rc = sqlite3_open(sFile.data(), &db);
	if( rc ){
#if 1
		kdDebug() << "Can't open database: " << sqlite3_errmsg(db) << endl;
#endif
		sqlite3_close(db);
		return;
	}
	rc = sqlite3_exec(db, sCommand.data(), NULL, NULL, &zErrMsg);
	if( rc!=SQLITE_OK ){
#if 1
		kdDebug() << "SQL error: " << zErrMsg << endl;
#endif
		sqlite3_free(zErrMsg);
	}
	sqlite3_close(db);
	return;
}

void SQLiteDB::execAll(const QString & sFile, QStringList & slCommand)
{
	char *zErrMsg = 0;
	int rc = sqlite3_open(sFile.data(), &db);
	if( rc ){
#ifdef NETDEBUG
		kdDebug() << "Can't open database: " << sqlite3_errmsg(db) << endl;
#endif
		sqlite3_close(db);
		return;
	}
	for ( QStringList::Iterator it = slCommand.begin(); it != slCommand.end(); ++it )
	{
		rc = sqlite3_exec(db, (*it).data(), NULL, NULL, &zErrMsg);
		if( rc!=SQLITE_OK ){
#ifdef NETDEBUG
			kdDebug() << "SQL error: " << zErrMsg << endl;
#endif
			sqlite3_free(zErrMsg);
		}
	}
	sqlite3_close(db);
	return;
}

void SQLiteDB::createMemoDB( const QString & sPath )
{
	// QString sFilePath;
	QStringList slQuery;

	sMemoFolders = sPath;
	sMemoFolders += "Folders.db";
	if ( !QFile(sMemoFolders).exists() )
	{
		execOne(sMemoFolders, "CREATE TABLE FOLDER (SN text, PSN text, FOLDERNAME text, FOLDERTYPE integer, FILENAME text, RESERVED text);");
	}

	sMemoInbox = sPath;
	sMemoInbox += "local_inbox.db";
	if ( !QFile(sMemoInbox).exists() )
	{
		slQuery.clear();
		slQuery.append("CREATE TABLE tb_local_inbox (UUID text unique, MID integer PRIMARY KEY AUTOINCREMENT, SUBJECT text, SUSER text, RUSER text, DATE text, SIZE integer, BODYDATA text, MSGTYPE text, UNREAD integer, CONFIRM text, ISPREINSERTED integer default 1, ISDELETED integer default 0, RESERVED text);");
		slQuery.append("CREATE INDEX IDX_ISDELETED on tb_local_inbox (ISDELETED);");
		slQuery.append("CREATE INDEX IDX_ISPREINSERTED on tb_local_inbox (ISPREINSERTED);");
		slQuery.append("CREATE INDEX IDX_PAGELIST on tb_local_inbox (ISDELETED, ISPREINSERTED, DATE);");
		slQuery.append("CREATE INDEX IDX_DATE on TB_local_inbox (DATE);");
		execAll(sMemoInbox, slQuery);
	}

	sMemoOutbox = sPath;
	sMemoOutbox += "local_outbox.db";
	if ( !QFile(sMemoOutbox).exists() )
	{
		slQuery.clear();
		slQuery.append("CREATE TABLE TB_local_outbox (UUID text unique, MID integer PRIMARY KEY AUTOINCREMENT, SUBJECT text, SUSER text, RUSER text, DATE text, SIZE integer, BODYDATA text, MSGTYPE text, UNREAD integer, CONFIRM text, ISPREINSERTED integer default 1, ISDELETED integer default 0, RESERVED text);");
		slQuery.append("CREATE INDEX IDX_ISDELETED on TB_local_outbox (ISDELETED);");
		slQuery.append("CREATE INDEX IDX_ISPREINSERTED on TB_local_outbox (ISPREINSERTED);");
		slQuery.append("CREATE INDEX IDX_PAGELIST on TB_local_outbox (ISDELETED, ISPREINSERTED, DATE);");
		slQuery.append("CREATE INDEX IDX_DATE on TB_local_outbox (DATE);");
		execAll(sMemoOutbox, slQuery);
	}
}

/*! 대화 저장 */
void SQLiteDB::createChatDB( const QString & sPath )
{
	// QString sFilePath;
	QStringList slQuery;

	sChatFolders = sPath;
	sChatFolders += "Folders.db";
	if ( !QFile(sChatFolders).exists() )
	{
		execOne(sChatFolders, "CREATE TABLE FOLDER (SN text, PSN text, FOLDERNAME text, FOLDERTYPE integer, FILENAME text, RESERVED text);");
	}

	sChatCount = sPath;
	sChatCount += "chat_count.db";
	if ( !QFile(sChatCount).exists() )
	{
		execOne(sChatCount, "CREATE TABLE TB_CHAT_RANKING (USERID text, CHATCOUNT integer);");
	}

	sChatBox = sPath;
	sChatBox += "local_chat.db";
	if ( !QFile(sChatBox).exists() )
	{
		slQuery.clear();
		slQuery.append("CREATE TABLE tb_local_chat (UUID text unique, MID integer PRIMARY KEY AUTOINCREMENT, CHATUSERS blob, BODYDATA blob, DATE text, SIZE integer, MSGTYPE text, ISPREINSERTED integer default 1, ISDELETED integer default 0, RESERVED text);");
		slQuery.append("CREATE INDEX IDX_ISDELETED on tb_local_chat (ISDELETED);");
		slQuery.append("CREATE INDEX IDX_ISPREINSERTED on tb_local_chat (ISPREINSERTED);");
		slQuery.append("CREATE INDEX IDX_PAGELIST on tb_local_chat (ISDELETED, ISPREINSERTED, DATE);");
		slQuery.append("CREATE INDEX IDX_DATE on TB_local_chat (DATE);");
		execAll(sChatBox, slQuery);
	}
}

void SQLiteDB::saveChatBox(QString sCHATUSERS, QString sBODYDATA)
{
	QString sUUID( QUuid::createUuid().toString().replace(QRegExp("[{}]"),"") );
	QString sDateTime( QDateTime::currentDateTime().toString( QString("yyyyMMddhhmmss") ) );
	QString sQuery;

/*!
  INSERT INTO "tb_local_inbox" VALUES('9853D932-5B16-46C7-8F73-D4DFF971A802',1,'심
  기신 수련','ring0320@nate.com','ring0320@nate.com','20070418115727',123,'[일정 >알림]
  2007년 4월 18일 수요일 오전 11:30 (매주반복)
  심기신 수련

  <link href="plugin://54E70798-B9FE-4e74-83F9-B11E1DE1DEF7">메모짱 실행하기</link>','nml',0,'n',0,0,'');
  --------
  0      1     2           3          4      5      6         7               8           9
  UUID | MID | CHATUSERS | BODYDATA | DATE | SIZE | MSGTYPE | ISPREINSERTED | ISDELETED | RESERVED
*/
	sQuery = "INSERT INTO \"tb_local_chat\" (UUID,CHATUSERS,BODYDATA,DATE,SIZE,MSGTYPE,ISPREINSERTED,ISDELETED,RESERVED) VALUES('";
	sQuery += sUUID.utf8(); // 0
	sQuery += "', '";
	sQuery += sCHATUSERS.utf8(); // 2
	sQuery += "', '";
	sQuery += sBODYDATA.utf8(); // 3
	sQuery += "', '";
	sQuery += sDateTime.utf8(); // 4
	sQuery += "', ";
	sQuery += QString::number( sBODYDATA.length() ); // 5
	sQuery += ", 'chat', 0, 0, '');"; // 6 7 8 9
	execOne(sChatBox, sQuery);
}

/*! 받은 쪽지 저장 */
void SQLiteDB::saveMemoInbox( QString sUUID, QString sSUSER, QString sRUSER, QString sBODYDATA, QString sIsUnread )
{
  
	// QString sUUID( QUuid::createUuid().toString().replace(QRegExp("[{}]"),"") );
	QString sDateTime( QDateTime::currentDateTime().toString( QString("yyyyMMddhhmmss") ) );
	QString sQuery;
	QString sSubject;

	/*! 쪽지 제목은 첫 줄 */
	QStringList slList = QStringList::split(QString("\n"), sBODYDATA);
	for ( QStringList::Iterator it = slList.begin(); it != slList.end(); ++it )
	{
		if ( (*it).length() > 1 )
		{
			sSubject = *it;
			break;
		}
	}

/*!
  INSERT INTO "tb_local_inbox" VALUES('9853D932-5B16-46C7-8F73-D4DFF971A802',1,'심
  기신 수련','ring0320@nate.com','ring0320@nate.com','20070418115727',123,'[일정 >알림]
  2007년 4월 18일 수요일 오전 11:30 (매주반복)
  심기신 수련

  <link href="plugin://54E70798-B9FE-4e74-83F9-B11E1DE1DEF7">메모짱 실행하기</link>','nml',0,'n',0,0,'');
  --------
  0      1     2         3       4       5      6      7
  UUID | MID | SUBJECT | SUSER | RUSER | DATE | SIZE | BODYDATA |
  8         9        10        11              12          13
  MSGTYPE | UNREAD | CONFIRM | ISPREINSERTED | ISDELETED | RESERVED
*/
	sQuery = "INSERT INTO \"tb_local_inbox\" (UUID,SUBJECT,SUSER,RUSER,DATE,SIZE,BODYDATA,MSGTYPE,UNREAD,CONFIRM,ISPREINSERTED,ISDELETED,RESERVED) VALUES('";
	sQuery += sUUID.utf8(); // 0
	sQuery += "', '";
	sSubject.replace("'", "''");
	sQuery += sSubject.utf8(); // 2
	sQuery += "', '";
	sQuery += sSUSER.utf8(); // 3
	sQuery += "', '";
	sQuery += sRUSER.utf8(); // 4
	sQuery += "', '";
	sQuery += sDateTime.utf8();  // 5
	sQuery += "', ";
	sQuery += QString::number( sBODYDATA.length() ); // 6
	sQuery += ", '";
	sBODYDATA.replace("'", "''");
	sQuery += sBODYDATA.utf8(); // 7
	//             8      9  10 11 12 13
	sQuery += "', 'text', ";
	sQuery += sIsUnread;
	sQuery += ", 0, 0, 0, '');";
	execOne(sMemoInbox, sQuery);
}

/*! 보낸 쪽지 저장 */
void SQLiteDB::saveMemoOutbox( const QString & sSUSER, QString sRUSER, QString sBODYDATA)
{
	QString sUUID( QUuid::createUuid().toString().replace(QRegExp("[{}]"),"") );
	QString sDateTime( QDateTime::currentDateTime().toString( QString("yyyyMMddhhmmss") ) );
	QString sQuery;
	QString sSubject;

	/*! 쪽지 제목은 첫 줄 */
	QStringList slList = QStringList::split(QString("\n"), sBODYDATA);
	for ( QStringList::Iterator it = slList.begin(); it != slList.end(); ++it )
	{
		if ( (*it).length() > 1 )
		{
			sSubject = *it;
			break;
		}
	}

/*!
  INSERT INTO "tb_local_inbox" VALUES('9853D932-5B16-46C7-8F73-D4DFF971A802',1,'심
  기신 수련','ring0320@nate.com','ring0320@nate.com','20070418115727',123,'[일정 >알림]
  2007년 4월 18일 수요일 오전 11:30 (매주반복)
  심기신 수련

  <link href="plugin://54E70798-B9FE-4e74-83F9-B11E1DE1DEF7">메모짱 실행하기</link>','nml',0,'n',0,0,'');
  --------
  0      1     2         3       4       5      6      7
  UUID | MID | SUBJECT | SUSER | RUSER | DATE | SIZE | BODYDATA |
  8         9        10        11              12          13
  MSGTYPE | UNREAD | CONFIRM | ISPREINSERTED | ISDELETED | RESERVED
*/
	sQuery = "INSERT INTO \"tb_local_outbox\" (UUID,SUBJECT,SUSER,RUSER,DATE,SIZE,BODYDATA,MSGTYPE,UNREAD,CONFIRM,ISPREINSERTED,ISDELETED,RESERVED) VALUES('";
	sQuery += sUUID.utf8(); // 0
	sQuery += "', '";
	sSubject.replace("'", "''");
	sQuery += sSubject.utf8(); // 2
	sQuery += "', '";
	sQuery += sSUSER.utf8(); // 3
	sQuery += "', '";
	sQuery += sRUSER.utf8(); // 4
	sQuery += "', '";
	sQuery += sDateTime.utf8();  // 5
	sQuery += "', ";
	sQuery += QString::number( sBODYDATA.length() ); // 6
	sQuery += ", '";
	sBODYDATA.replace("'", "''");
	sQuery += sBODYDATA.utf8(); // 7
	//             8      9  10 11 12 13
	sQuery += "', 'text', 1, 0, 0, 0, '');";
	execOne(sMemoOutbox, sQuery);
}

rowList SQLiteDB::getRecords( const QString & sFile, const QString & sQuery )
{
	sqlite3_stmt *vm;
	const char *tail;
	int ncol;
	QStringList r;
	int err=0;
	browseRecs.clear();
	idmap.clear();
	
#ifdef NETDEBUG
	kdDebug() << "[ D B  F I L E] [" << sFile << "]" << endl;
	kdDebug() << "[ Q U E R Y ] [" << sQuery << "]" << endl;
#endif
	int rc = sqlite3_open(sFile.data(), &db);
	if( rc ){
#ifdef NETDEBUG
		kdDebug() << "Can't open database: " << sqlite3_errmsg(db) << endl;
#endif
		sqlite3_close(db);
		return browseRecs;
	}

	err=sqlite3_prepare(db, sQuery.utf8(), -1, &vm, &tail);
	if (err == SQLITE_OK){
		int rownum = 0;
		while ( sqlite3_step(vm) == SQLITE_ROW ){
			r.clear();
			ncol = sqlite3_data_count(vm);
			for (int e=0; e<ncol; e++){
				QString rv(QString::fromUtf8((const char *) sqlite3_column_text(vm, e)));
				r << rv;
				if (e==0){
					idmap.insert(rv.toInt(),rownum);
					rownum++;
				}
			}
			browseRecs.append(r);
		}

		sqlite3_finalize(vm);
	} /*else{
		lastErrorMessage = QString ("could not get fields");
		} */
	sqlite3_close(db);
	return browseRecs;
}

void SQLiteDB::createUserDB(const QString & sPath)
{
	QStringList slQuery;

	sUserDB = sPath;
	sUserDB += "local_user.db";
#ifdef NETDEBUG
	kdDebug() << "[ F I L E P A T H ] [" << sUserDB << "]" << endl;
#endif
	if ( !QFile( sUserDB ).exists() )
	{
		slQuery.clear();
		slQuery.append("CREATE TABLE tb_user (ID text  primary key, NAME text, NICK text, EMAIL text);");
		slQuery.append("CREATE INDEX IDX_NAME on tb_user (NAME);");
		slQuery.append("CREATE INDEX IDX_NICK on tb_user (NICK);");
		slQuery.append("CREATE INDEX IDX_EMAIL on tb_user (EMAIL);");
		execAll(sUserDB, slQuery);
	}
}


/*!
  P2P DB 스키마
  http://spreadsheets.google.com/pub?key=pQ6CbePpTZSrC0cr7H2-lfw&gid=1
*/
void SQLiteDB::createP2PDB( const QString &sPath )
{
    QStringList slQuery;

    sP2PDB = sPath;
    sP2PDB += "p2p.db";
#if 1
	kdDebug() << "[ F I L E P A T H ] [" << sP2PDB << "]" << endl;
#endif
	if ( !QFile( sP2PDB ).exists() )
	{
		slQuery.clear();
        slQuery.append( "CREATE TABLE tb_p2p ('File_Cookie' TEXT PRIMARY KEY NOT NULL,\
'File_Name' TEXT DEFAULT NULL,                                          \
'File_Size' INTEGER DEFAULT 0,                                          \
'File_Received_Size' INTEGER DEFAULT 0,                                 \
'File_Local_Path' TEXT NOT NULL,                                        \
'P2P_Cookie' TEXT DEFAULT NULL,                                           \
'P2P_Type' TEXT DEFAULT 'S',                                            \
'P2P_Status' TEXT DEFAULT 'S',                                          \
'Source_ID' TEXT NOT NULL,                                              \
'Source_P2P_IP' TEXT DEFAULT NULL,                                      \
'Source_P2P_Port' INTEGER DEFAULT 5004,                                 \
'Source_P2P_Negotiation_Port' INTEGER DEFAULT 6004,                     \
'Destination_ID' TEXT NOT NULL,                                         \
'Destination_P2P_IP' TEXT DEFAULT NULL,                                 \
'Destination_P2P_Port' INTEGER DEFAULT 5004,                            \
'Destination_P2P_Negotiation_Port' INTEGER DEFAULT 6004,                \
'Created_Date' DATETIME DEFAULT NULL,                                   \
'Start_Date' DATETIME DEFAULT NULL,                                     \
'End_Date' DATETIME DEFAULT NULL );");
        
        slQuery.append("CREATE INDEX IDX_P2P_Cookie on tb_p2p (P2P_Cookie);");
        slQuery.append("CREATE INDEX IDX_P2P_Type on tb_p2p (P2P_Type);");
        slQuery.append("CREATE INDEX IDX_P2P_Status on tb_p2p (P2P_Status);");
        slQuery.append("CREATE INDEX IDX_Source_ID on tb_p2p (Source_ID);");
        slQuery.append("CREATE INDEX IDX_Destination_ID on tb_p2p (Destination_ID);");

		execAll(sP2PDB, slQuery);
	}
}

/*!
  knateon: KEY : [seq], VALUE : [392073805]
  knateon: KEY : [uuid], VALUE : [110E385A-2A40-4AA1-83B5-E764EBFC102E]
  knateon: KEY : [from_id], VALUE : [ring0320]
  map["from_full_id"] = pBuddy->getUID();
  knateon: KEY : [from_cmn], VALUE : [10014827278]
  knateon: KEY : [to_ids], VALUE : [ring0320@lycos.co.kr]
  knateon: KEY : [confirm], VALUE : [N]
  knateon: KEY : [recv_date], VALUE : [20070619144533]
  knateon: KEY : [subject], VALUE : [#%20버디리스트%20정렬.]
  knateon: KEY : [content_type], VALUE : [TEXT]
  knateon: KEY : [content], VALUE : [#%20버디리스트%20정렬.%0D%0A#%20채팅창이%20활성화%20되지%20않은%20상태에서%20메세지%20오면%20창%20깜빡이고%20소리%20들리게%20하기.%0D%0A%0D%0A%20%20%20%20*%20창이%20활성화%20되었는지%20유무%20확인%20필요.%0D%0A%0D%0A#%20MVBG%20:%20버디%20이동%20(여러명)%0D%0ARMVB%20:%20버디%20삭제%20(여러명)%0D%0ACPBG%20:%20버디%20복사%20(여러명)%0D%0A#%20버튼%20메뉴%20disable%20/%20enable%0D%0A#%20폰트,%20글자색?%20어떻게?%0D%0A#%20미니홈피%20닫히지%20않음.%0D%0A#%20이모티콘%20convert%20?%20보이는것과%20저장하는것을%20틀리게...%0D%0A%0D%0A%20%20%20%20*%20QTextEdit%20를%20상속받아서...%20저장Text와%20보이는%20Text를%20따로%20저장...%0D%0A%0D%0A#%20버디리스트에%20미니홈피,%0D%0A#%20쪽지%20-%20오프리인%20쪽지%20서버에서%20가져오기.%0D%0A#%20내%20프로필%20보기/설정]
*/
void SQLiteDB::saveMemoInbox(QMap< QString, QString > & mData)
{
	QString sQuery( "INSERT INTO \"tb_local_inbox\" (UUID,SUBJECT,SUSER,RUSER,DATE,SIZE,BODYDATA,MSGTYPE,UNREAD,CONFIRM,ISPREINSERTED,ISDELETED,RESERVED) VALUES('" );
	sQuery += mData["uuid"].utf8(); // sUUID.utf8(); // 0
	sQuery += "', '";
	mData["subject"].replace("'", "''");
	sQuery += mData["subject"].utf8(); // sSubject.utf8(); // 2
	sQuery += "', '";
	sQuery += mData["from_full_id"].utf8(); // sSUSER.utf8(); // 3
	sQuery += "', '";
	sQuery += mData["to_ids"].utf8(); // sRUSER.utf8(); // 4
	sQuery += "', '";
	sQuery += mData["recv_date"].utf8(); // sDateTime.utf8();  // 5
	sQuery += "', ";
	sQuery += QString::number( mData["content"].length() ); // 6
	sQuery += ", '";
	mData["content"].replace("'", "''");
	sQuery += mData["content"].utf8(); // sBODYDATA.utf8(); // 7
	//             8      9  10 11 12 13
	sQuery += "', 'text', 1, 0, 0, 0, '');";
#ifdef NETDEBUG
	kdDebug() << "[ Q U E R Y ]:[" << sQuery << "]" << endl;
#endif
	execOne(sMemoInbox, sQuery);
}

int SQLiteDB::getNewMemoCount()
{
	rowList myList;
	myList = getRecords(sMemoInbox, "SELECT COUNT(*) FROM tb_local_inbox WHERE UNREAD=1;");
	return myList.first()[0].toInt();
}

void SQLiteDB::deleteMemoInbox(const QString & sUUID)
{
	QString sQuery;
	sQuery = "DELETE FROM tb_local_inbox WHERE UUID='";
	sQuery += sUUID;
	sQuery += "';";
	execOne( sMemoInbox, sQuery );
}

#include "sqlitedb.moc"


