/*	WebDownloader for X-Window
 *	Copyright (C) 1999-2002 Koshelev Maxim
 *	This Program is free but not GPL!!! You can't modify it
 *	without agreement with author. You can't distribute modified
 *	program but you can distribute unmodified program.
 *
 *	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.
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include "schedule.h"
#include "dbc.h"
#include "locstr.h"
#include "main.h"
#include "savedvar.h"
#include "var.h"
#include "face/list.h"
#include "face/fsched.h"
#include "savelog.h"

d4xScheduler *MainScheduler=(d4xScheduler *)NULL;

d4xSchedAction::~d4xSchedAction(){
	if (iter) gtk_tree_iter_free(iter);
};

int d4xSchedAction::load(int fd){
	tSavedVar table_of_fields[]={
		{"start_time",	SV_TYPE_TIME,	&start_time},
		{"period",	SV_TYPE_TIME,	&period},
		{"retries",	SV_TYPE_INT,	&retries},
		{"end.",	SV_TYPE_END,	NULL}
	};
	char buf[MAX_LEN];
	while(f_rstr(fd,buf,MAX_LEN)>0){
		unsigned int i;
		for (i=0;i<sizeof(table_of_fields)/sizeof(tSavedVar);i++){
			if (equal_uncase(buf,table_of_fields[i].name)){
				if (table_of_fields[i].type==SV_TYPE_END)
					return(0);
				else{
					if (sv_parse_file(fd,&(table_of_fields[i]),buf,MAX_LEN))
						return(-1);
				};
					
			};
		};
	};
	return(-1);
};

int d4xSchedAction::save(int fd){
	if (write_named_time(fd,"start_time",start_time))
		return(-1);
	if (write_named_time(fd,"period",period))
		return(-1);
	if (write_named_integer(fd,"retries",retries))
		return(-1);
	if (f_wstr_lf(fd,"end.")<=0)
		return(-1);
	return(0);
};

/*------------------------------------------------------------*/
int d4xSASpeed::type(){
	return(SACT_SET_SPEED);
};

int d4xSASpeed::load(int fd){
	tSavedVar table_of_fields[]={
		{"start_time",	SV_TYPE_TIME,	&start_time},
		{"period",	SV_TYPE_TIME,	&period},
		{"retries",	SV_TYPE_INT,	&retries},
		{"speed",	SV_TYPE_INT,	&speed},
		{"end.",	SV_TYPE_END,	NULL}
	};
	char buf[MAX_LEN];
	while(f_rstr(fd,buf,MAX_LEN)>0){
		unsigned int i;
		for (i=0;i<sizeof(table_of_fields)/sizeof(tSavedVar);i++){
			if (equal_uncase(buf,table_of_fields[i].name)){
				if (table_of_fields[i].type==SV_TYPE_END)
					return(0);
				else{
					if (sv_parse_file(fd,&(table_of_fields[i]),buf,MAX_LEN))
						return(-1);
				};
					
			};
		};
	};
	return(-1);
};

int d4xSASpeed::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_speed:")<=0)
		return(-1);
	if (write_named_integer(fd,"speed",speed))
		return(-1);	
	return(d4xSchedAction::save(fd));
};

void d4xSASpeed::run(tMain *papa){
	papa->set_speed(speed);
};
/*------------------------------------------------------------*/

int d4xSAPopup::type(){
	return(SACT_POPUP_WINDOW);
};

int d4xSAPopup::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_popup:")<=0)
		return(-1);
	return(d4xSchedAction::save(fd));
};

void d4xSAPopup::run(tMain *papa){
	main_window_popup();
};
/*-----------------------------------------------------------*/
int d4xSAExit::type(){
	return(SACT_EXIT);
};

int d4xSAExit::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_exit:")<=0)
		return(-1);
	return(d4xSchedAction::save(fd));
};

void d4xSAExit::run(tMain *papa){
	//hehe nothing to do here :-)
};
/*------------------------------------------------------------*/
int d4xSADelCompleted::type(){
	return(SACT_DEL_COMPLETED);
};

int d4xSADelCompleted::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_del_completed:")<=0)
		return(-1);
	return(d4xSchedAction::save(fd));
};

void d4xSADelCompleted::run(tMain *papa){
        papa->del_completed();
};
/*------------------------------------------------------------*/
int d4xSADelFailed::type(){
	return(SACT_DEL_FAILED);
};

int d4xSADelFailed::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_del_failed:")<=0)
		return(-1);
	return(d4xSchedAction::save(fd));
};

void d4xSADelFailed::run(tMain *papa){
	papa->del_fataled();
};
/*------------------------------------------------------------*/
d4xSAAddDownload::d4xSAAddDownload():d4xSchedAction(){
	dwn=NULL;
};

int d4xSAAddDownload::type(){
	return(SACT_ADD_DOWNLOAD);
};

int d4xSAAddDownload::load(int fd){
	tSavedVar table_of_fields[]={
		{"start_time",	SV_TYPE_TIME,	&start_time},
		{"period",	SV_TYPE_TIME,	&period},
		{"retries",	SV_TYPE_INT,	&retries},
		{"Download:",	SV_TYPE_DOWNLOAD, &dwn},
		{"end.",	SV_TYPE_END,	NULL}
	};
	char buf[MAX_LEN];
	while(f_rstr(fd,buf,MAX_LEN)>0){
		unsigned int i;
		for (i=0;i<sizeof(table_of_fields)/sizeof(tSavedVar);i++){
			if (equal_uncase(buf,table_of_fields[i].name)){
				if (table_of_fields[i].type==SV_TYPE_END)
					return(0);
				else{
					if (sv_parse_file(fd,&(table_of_fields[i]),buf,MAX_LEN))
						return(-1);
				};
					
			};
		};
	};
	return(-1);
};

int d4xSAAddDownload::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_add_download:")<=0)
		return(-1);
	if (dwn) dwn->save_to_config(fd);
	return(d4xSchedAction::save(fd));
};

void d4xSAAddDownload::run(tMain *papa){
	if (dwn){
		tDownload *dwn_copy=new tDownload;
		dwn_copy->copy(dwn);
		if (papa->add_downloading(dwn_copy)) delete(dwn_copy);
	};
};

d4xSAAddDownload::~d4xSAAddDownload(){
	if (dwn) delete(dwn);
};
/*------------------------------------------------------------*/
int d4xSAUrl::load(int fd){
	tSavedVar table_of_fields[]={
		{"start_time",	SV_TYPE_TIME,	&start_time},
		{"period",	SV_TYPE_TIME,	&period},
		{"retries",	SV_TYPE_INT,	&retries},
		{"URL:",	SV_TYPE_URL,	&url},
		{"end.",	SV_TYPE_END,	NULL}
	};
	char buf[MAX_LEN];
	while(f_rstr(fd,buf,MAX_LEN)>0){
		unsigned int i;
		for (i=0;i<sizeof(table_of_fields)/sizeof(tSavedVar);i++){
			if (equal_uncase(buf,table_of_fields[i].name)){
				if (table_of_fields[i].type==SV_TYPE_END)
					return(0);
				else{
					if (sv_parse_file(fd,&(table_of_fields[i]),buf,MAX_LEN))
						return(-1);
				};
			};
		};
	};
	return(-1);
};

int d4xSAUrl::save(int fd){
	f_wstr_lf(fd,"URL:");
	f_wstr_lf(fd,std::string(url).c_str());
	return(d4xSchedAction::save(fd));	
};

//  working with downloads

d4xSADelDownload::d4xSADelDownload():d4xSAUrl(){
};

int d4xSADelDownload::type(){
	return(SACT_DELETE_DOWNLOAD);
};

int d4xSADelDownload::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_del_download:")<=0)
		return(-1);
	return(d4xSAUrl::save(fd));
};

void d4xSADelDownload::run(tMain *papa){
	papa->delete_download_url(url);
};
/*------------------------------------------------------------*/
d4xSADelIfCompleted::d4xSADelIfCompleted():d4xSAUrl(){
};

int d4xSADelIfCompleted::type(){
	return(SACT_DEL_IF_COMPLETED);
};

int d4xSADelIfCompleted::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_del_if_completed:")<=0)
		return(-1);
	return(d4xSAUrl::save(fd));
};

void d4xSADelIfCompleted::run(tMain *papa){
	tDownload *tmp=papa->find_url(url);
	if (tmp && tmp->owner()==DL_COMPLETE)
		papa->delete_download(tmp);
};
/*------------------------------------------------------------*/
d4xSARunDownload::d4xSARunDownload():d4xSAUrl(){
};

int d4xSARunDownload::type(){
	return(SACT_RUN_DOWNLOAD);
};

int d4xSARunDownload::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_run_download:")<=0)
		return(-1);
	return(d4xSAUrl::save(fd));
};

void d4xSARunDownload::run(tMain *papa){
	papa->continue_download_url(url);
};
/*------------------------------------------------------------*/
d4xSAStopDownload::d4xSAStopDownload():d4xSAUrl(){
};

int d4xSAStopDownload::type(){
	return(SACT_PAUSE_DOWNLOAD);
};

int d4xSAStopDownload::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_stop_download:")<=0)
		return(-1);
	return(d4xSAUrl::save(fd));
};

void d4xSAStopDownload::run(tMain *papa){
	papa->stop_download_url(url);
};
/*------------------------------------------------------------*/

int d4xSASaveList::type(){
	return(SACT_SAVE_LIST);
};

int d4xSASaveList::load(int fd){
	tSavedVar table_of_fields[]={
		{"start_time",	SV_TYPE_TIME,	&start_time},
		{"period",	SV_TYPE_TIME,	&period},
		{"retries",	SV_TYPE_INT,	&retries},
		{"path",	SV_TYPE_PSTR,	&path},
		{"end.",	SV_TYPE_END,	NULL}
	};
	char buf[MAX_LEN];
	while(f_rstr(fd,buf,MAX_LEN)>0){
		unsigned int i;
		for (i=0;i<sizeof(table_of_fields)/sizeof(tSavedVar);i++){
			if (equal_uncase(buf,table_of_fields[i].name)){
				if (table_of_fields[i].type==SV_TYPE_END)
					return(0);
				else{
					if (sv_parse_file(fd,&(table_of_fields[i]),buf,MAX_LEN))
						return(-1);
				};
					
			};
		};
	};
	return(-1);
};

int d4xSASaveList::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_save_list:")<=0)
		return(-1);
	if (path.get())
		write_named_string(fd,"path",path.get());
	return(d4xSchedAction::save(fd));
};

void d4xSASaveList::run(tMain *papa){
	if (path.get())
		save_list_to_file(path.get());
};
/*------------------------------------------------------------*/
int d4xSAExecute::type(){
	return(SACT_EXECUTE);
};

int d4xSAExecute::load(int fd){
	tSavedVar table_of_fields[]={
		{"start_time",	SV_TYPE_TIME,	&start_time},
		{"period",	SV_TYPE_TIME,	&period},
		{"retries",	SV_TYPE_INT,	&retries},
		{"command",	SV_TYPE_PSTR,	&command},
		{"end.",	SV_TYPE_END,	NULL}
	};
	char buf[MAX_LEN];
	while(f_rstr(fd,buf,MAX_LEN)>0){
		unsigned int i;
		for (i=0;i<sizeof(table_of_fields)/sizeof(tSavedVar);i++){
			if (equal_uncase(buf,table_of_fields[i].name)){
				if (table_of_fields[i].type==SV_TYPE_END)
					return(0);
				else{
					if (sv_parse_file(fd,&(table_of_fields[i]),buf,MAX_LEN))
						return(-1);
				};
					
			};
		};
	};
	return(-1);
};

int d4xSAExecute::save(int fd){
	if (f_wstr_lf(fd,"d4x_sa_execute:")<=0)
		return(-1);
	if (command.get())
		write_named_string(fd,"command",command.get());
	return(d4xSchedAction::save(fd));
};

static void *_sa_exec_run_(void *what){
	d4xSAExecute *act=(d4xSAExecute *)what;
	system(act->command.get());
	pthread_exit(NULL);
	return(NULL);
};

void d4xSAExecute::run(tMain *papa){
	if (command.get()){
		pthread_attr_t attr_p;
		pthread_t thread_id;
		pthread_attr_init(&attr_p);
		pthread_attr_setdetachstate(&attr_p,PTHREAD_CREATE_DETACHED);
		pthread_attr_setscope(&attr_p,PTHREAD_SCOPE_SYSTEM);
		pthread_create(&thread_id,&attr_p,
			       _sa_exec_run_,(void *)this);
	};
};
/**************************************************************/

d4xScheduler::d4xScheduler(){
	FIRST=NULL;
	changed=0;
};

d4xScheduler::~d4xScheduler(){
	while (FIRST){
		d4xSchedAction *tmp=FIRST;
		del_action(tmp);
		delete(tmp);
	};
};

void d4xScheduler::add_scheduled(tDownload *what){
	d4xSAAddDownload *act=new d4xSAAddDownload;
	act->dwn=what;
	act->start_time=what->ScheduleTime;
	act->period=0;
	act->retries=0;
	add_action(act);
};

void d4xScheduler::add_action(d4xSchedAction *act){
	DBC_RETURN_IF_FAIL(act!=NULL);
	changed=1;
	act->lock=0;
	if (FIRST){
		d4xSchedAction *tmp=FIRST;
		while (tmp->next){
			if (tmp->start_time>act->start_time)
				break;
			tmp=tmp->next;
		};
		if (tmp->start_time>act->start_time){
			act->next=tmp;
			if ((act->prev=tmp->prev))
				act->prev->next=act;
			else
				FIRST=act;
			tmp->prev=act;
		}else{
			act->prev=tmp;
			tmp->next=act;
			act->next=NULL;
		};
		d4x_scheduler_insert(act,act->prev);
	}else{
		FIRST=act;
		act->next=act->prev=NULL;
		d4x_scheduler_insert(act,NULL);
	};
};

void d4xScheduler::del_action(d4xSchedAction *act){
	DBC_RETURN_IF_FAIL(act!=NULL);
	changed=1;
	if (act->prev)
		act->prev->next=act->next;
	else
		FIRST=act->next;
	if (act->next)
		act->next->prev=act->prev;
	d4x_scheduler_remove(act);
};

void d4xScheduler::redraw(){
	d4xSchedAction *tmp=FIRST;
	while (tmp){
		d4x_scheduler_insert(tmp,tmp->prev);
		tmp=tmp->next;
	};
};

int d4xScheduler::save(int fd){
	d4xSchedAction *tmp=FIRST;
	while (tmp){
		if (tmp->save(fd))
			return(-1);
		tmp=tmp->next;
	};
	return(0);
};

void d4xScheduler::clear_old(){
	time_t now=time(NULL);
	d4xSchedAction *tmp=FIRST;
	while(tmp){
		d4xSchedAction *next=tmp->next;
		if (now>tmp->start_time){
			del_action(tmp);
			while (tmp->start_time<now && tmp->retries!=0){
				tmp->start_time+=tmp->period;
				if (tmp->retries>0)
					tmp->retries-=1;
			};
			if (tmp->retries==0)
				delete(tmp);
			else
				add_action(tmp);
		}else{
			break;
		};
		tmp=next;
	};
};

void d4xScheduler::run(tMain *papa){
	time_t now=time(NULL);
	int a=0; //counter
	d4xSchedAction *tmp=FIRST;
	int exit_flag=0;
	int se=0;
	while (tmp){
		if (now>tmp->start_time){
			d4xSchedAction *next=tmp->next;
			se=1;
			if (tmp->lock==0){ //if no editors opened
				tmp->run(papa);
				del_action(tmp);
				while (tmp->start_time<now && tmp->retries!=0){
					tmp->start_time+=tmp->period;
					if (tmp->retries>0)
						tmp->retries-=1;
				};
				if (tmp->type()==SACT_EXIT)
					exit_flag=1;
				if (tmp->retries==0)
					delete(tmp);
				else
					add_action(tmp);
			};
			tmp=next;
			if (a++>10) break;
		}else
			break;
		if (exit_flag)
			break;
	};
	if (se && changed)
		save();
	if (exit_flag){
		my_main_quit();
//		_aa_.run_after_quit();
		exit(0);
	};
};

int d4xScheduler::load(int fd){
	char *table_of_fields[]={
		"d4x_sa_speed:",
		"d4x_sa_popup:",
		"d4x_sa_exit:",
		"d4x_sa_del_completed:",
		"d4x_sa_del_failed:",
		"d4x_sa_run_download:",
		"d4x_sa_stop_download:",
		"d4x_sa_del_download:",
		"d4x_sa_del_if_completed:",
		"d4x_sa_add_download:",
		"d4x_sa_save_list:",
		"d4x_sa_execute:"
	};
	char buf[MAX_LEN];
	d4xSchedAction *action=(d4xSchedAction *)NULL;
	while(f_rstr(fd,buf,MAX_LEN)>0){
		unsigned int i;
		for (i=0;i<sizeof(table_of_fields)/sizeof(char *);i++){
			if (equal_uncase(buf,table_of_fields[i])){
				switch(i){
				case SACT_SET_SPEED:
					action=new d4xSASpeed;
					break;
				case SACT_POPUP_WINDOW:
					action=new d4xSAPopup;
					break;
				case SACT_EXIT:
					action=new d4xSAExit;
					break;
				case SACT_DEL_COMPLETED:
					action=new d4xSADelCompleted;
					break;
				case SACT_DEL_FAILED:
					action=new d4xSADelFailed;
					break;
				case SACT_RUN_DOWNLOAD:
					action=new d4xSARunDownload;
					break;
				case SACT_PAUSE_DOWNLOAD:
					action=new d4xSAStopDownload;
					break;
				case SACT_DELETE_DOWNLOAD:
					action=new d4xSADelDownload;
					break;
				case SACT_DEL_IF_COMPLETED:
					action=new d4xSADelIfCompleted;
					break;
				case SACT_ADD_DOWNLOAD:
					action=new d4xSAAddDownload;
					break;
				case SACT_SAVE_LIST:
					action=new d4xSASaveList;
					break;
				case SACT_EXECUTE:
					action=new d4xSAExecute;
					break;
				};
			};
		};
		if (action){
			if (action->load(fd)==0)
				add_action(action);
			else
				delete(action);
			action=NULL;
		};
	};
	return(0);
};

void d4xScheduler::save(){
	if (!HOME_VARIABLE)
		return;
	char *path=sum_strings(HOME_VARIABLE,"/",CFG_DIR,"/","Scheduler",NULL);
	int fd=open(path,O_TRUNC | O_CREAT |O_RDWR,S_IRUSR | S_IWUSR);
	if (fd>=0){
		save(fd);
		close(fd);
	};
	delete[] path;
};

void d4xScheduler::load(){
	if (!HOME_VARIABLE)
		return;
	char *path=sum_strings(HOME_VARIABLE,"/",CFG_DIR,"/","Scheduler",NULL);
	int fd=open(path,O_RDONLY,S_IRUSR | S_IWUSR);
	if (fd>=0){
		load(fd);
		close(fd);
	};
	delete[] path;
};


syntax highlighted by Code2HTML, v. 0.9.1