/*
Facebook plugin for Miranda Instant Messenger
_____________________________________________
Copyright � 2009-11 Michal Zelinka, 2011-16 Robert P�sel
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, see .
*/
#include "constants.h"
#pragma once
#define FORCE_DISCONNECT 1
#define FORCE_QUIT 2
class facebook_client
{
public:
	////////////////////////////////////////////////////////////
	// Client definition
	facebook_client()
	{
		msgid_ = error_count_ = last_feeds_update_ = last_notification_time_ = random_ = chat_msgs_recv_ = chat_req_ = 0;
		buddies_lock_ = send_message_lock_ = notifications_lock_ = cookies_lock_ = NULL;
		hMsgCon = NULL;
		hFcbCon = NULL;
		fcb_conn_lock_ = NULL;
		handle_ = NULL;
		parent = NULL;
		mbasicWorks = true;
	}
	HANDLE hMsgCon;
	HANDLE hFcbCon;
	HANDLE fcb_conn_lock_;
	// Random generator value for this client
	unsigned int random_;
	// Parent handle
	FacebookProto*  parent;
	// User data
	facebook_user   self_;
	std::string username_;
	std::string password_;
	std::string dtsg_;
	std::string ttstamp_;
	std::string logout_hash_;
	std::string chat_channel_;
	std::string chat_channel_host_;
	std::string chat_channel_partition_;
	std::string chat_sequence_num_;
	std::string chat_reconnect_reason_;
	std::string chat_sticky_num_;
	std::string chat_sticky_pool_;
	std::string chat_conn_num_;
	std::string chat_clientid_;
	std::string chat_traceid_;
	time_t last_feeds_update_;
	time_t last_notification_time_;
	volatile unsigned int msgid_;
	int chat_msgs_recv_;
	volatile unsigned int chat_req_;
	bool mbasicWorks;
	////////////////////////////////////////////////////////////
	// Client vs protocol communication
	void    client_notify(TCHAR* message);
	////////////////////////////////////////////////////////////
	// Cookies, Data storage
	HANDLE cookies_lock_;
	std::map cookies;
	std::map pages;
	std::map chat_rooms;
	std::map notifications;
	// Contact/thread id caches
	std::map thread_id_to_user_id;
	std::map chat_id_to_hcontact;
	std::map user_id_to_hcontact;
	std::string get_newsfeed_type();
	std::string get_server_type();
	std::string get_privacy_type();
	std::set ignore_read;
	std::set typers;		// store info about typing contacts, because Facebook doesn't send "stopped typing" event when there is actual message being sent
	std::map readers;
	char*   load_cookies();
	void    store_headers(http::response* resp, NETLIBHTTPHEADER* headers, int headers_count);
	void    clear_cookies();
	void	clear_notifications();
	void	clear_chatrooms();
	void	clear_readers();
	void	insert_reader(MCONTACT, time_t, const std::tstring &reader = _T(""));
	void	erase_reader(MCONTACT);
	////////////////////////////////////////////////////////////
	// Connection handling
	unsigned int error_count_;
	bool    handle_entry(const std::string &method);
	bool    handle_success(const std::string &method);
	bool    handle_error(const std::string &method, int force_disconnect = 0);
	void __inline increment_error() { this->error_count_++; }
	void __inline decrement_error() { if (error_count_ > 0) error_count_--; }
	void __inline reset_error() { error_count_ = 0; }
	////////////////////////////////////////////////////////////
	// Helpers for data
	std::string __inline __dyn() {
		return ""; // FIXME: What's this value and where it come from? Looks like it is the same through all requests.
	}
	std::string __inline __req() {
		// Increment request number and convert it to string with radix 36 (whole numbers + whole alphabet)
		char buffer[10];
		itoa(InterlockedIncrement(&this->chat_req_), buffer, 36);
		return std::string(buffer);
	}
	std::string __inline __rev() {
		return "1911928"; // FIXME: Some version of communication protocol? On 1.9.2015 was used "1911928"
	}
	////////////////////////////////////////////////////////////
	// Login handling
	bool    login(const char *username, const char *password);
	bool    logout();
	const std::string & get_username() const;
	////////////////////////////////////////////////////////////
	// Session handling
	bool    home();
	bool    reconnect();
	bool    chat_state(bool online = true);
	////////////////////////////////////////////////////////////
	// Updates handling
	List::List buddies;
	HANDLE  buddies_lock_;
	HANDLE  send_message_lock_;
	HANDLE  notifications_lock_;
	////////////////////////////////////////////////////////////
	// Messages handling
	std::map messages_ignore;
	std::map messages_timestamp;
	bool    channel();
	bool	activity_ping();
	int		send_message(int seqid, MCONTACT, const std::string &message_text, std::string *error_text, const std::string &captchaPersistData = "", const std::string &captcha = "");
	////////////////////////////////////////////////////////////
	// Status handling
	bool    post_status(status_data *data);
	////////////////////////////////////////////////////////////
	// HTTP communication
	http::response flap(RequestType request_type, std::string *post_data = NULL, std::string *get_data = NULL);
	bool save_url(const std::string &url,const std::tstring &filename, HANDLE &nlc);
	bool notify_errors(RequestType);
	std::string choose_server(RequestType);
	std::string choose_action(RequestType, std::string *get_data = NULL);
	NETLIBHTTPHEADER *get_request_headers(int request_type, int *headers_count);
	////////////////////////////////////////////////////////////
	// Netlib handle
	HANDLE handle_;
	void set_handle(HANDLE h)
	{
		handle_ = h;
	}
};