#!/usr/bin/perl
# ----------------------------------------------------------------------------
#
#  (c) Copyright 2006 TradeExtender
# 
#  This software is proprietary to and embodies the confidential technology 
#  of TradeExtender. Possession, use, duplication or dissemination of the 
#  software and media is authorized only pursuant to a valid written license 
#  from TradeExtender.
#

use strict;
use lib "/var/www/vhosts/kantelpunten.com/httpdocs/pl/lib";
use lib "lib";
BEGIN {
    delete $INC{"Kantelpunten/Helper.pm"};
    delete $INC{"Kantelpunten/Process.pm"};
    delete $INC{"Kantelpunten/IntraDay.pm"};
    delete $INC{"Kantelpunten/News.pm"};
    delete $INC{"Kantelpunten/MyTask.pm"};
    delete $INC{"Kantelpunten/Mailer.pm"};
}

use IO::Seekable;
use IO::Dir;
use POSIX qw(strftime mktime);
use Kantelpunten::Helper;
use Kantelpunten::Process;
use Kantelpunten::IntraDay;
use Kantelpunten::News;
use Kantelpunten::MyTask;
use Kantelpunten::Mailer;
use Cwd;
#use Data::Dumper;
use CGI qw(:standard);

use constant ONE_DAY => 24 * 3600;

our $check_create_time;		# time to check for new creating of tasks!

# next update time, prev_time, spare, spare
our $update_rec      = "L L L5 A64";    
our $update_rec_len  = length pack($update_rec, 0, 0,   0, 0, 0, 0, 0, "");

local our $remote_ip;
local our $cur_time = time();
local our $update_file = get_private_dir() . "data/update.dat";
local our $update_time = undef;
local our $old_prev_time = undef;
local our $new_prev_time = undef;
local our $update_stocks = undef;
local our $param;
local our $verbose = 1;
local our $test = 0;

BEGIN{
	$check_create_time = time();
}
update();
exit(0);

sub update()
{
	# check for parameters 
	my $q = CGI->new;
	$param->{stock} = $q->param('stock');

	$remote_ip = init_helper();
	init_task('check');
	
	log_info("Update called", undef, 'updater');

	# get the send_mails file to check if a auto refresh is needed
	my $file = get_next_send_mails();
    my $refresh;    
	$refresh = "30;URL=http://www.kantelpunten.com/pl/Update.pl" if (defined($file) && is_outside_stock_hours());

	my $title = "Kantelpunten - Elke dag nieuwe adviezen voor de actieve belegger.";
	my $desc  = "Kantelpunten de beurscanner wordt elke dag automatisch geupdate met de laatste adviezen." .
	            " Alle informatie zoals nieuws, technische signalen, daghandel en aandeel informatie." .
	            " Overzichtelijke overzichten van de historische adviezen direct beschikbaar en volledig te controleren. ".
	            " Geen vage lijsten achteraf maar vooraf inzage.";
	print_header("+1s");
	print_pre_doc();
	print_head($title, undef, undef, undef, undef, undef, undef, $refresh, $desc);
	print_body(defined($param->{stock}) ? "overig" : "nav");
	print "<br><br><span class=\"l_blue\"><big>\n";
	print "Interne pagina bezoek <a href=\"http://www.kantelpunten.com\" target=\"_top\" rel=\"nofollow\">Kantelpunten de beursscanner</a>\n";
	print "</big></span>\n"; 
	print_body("end_no_stat");
	print_post_doc();

	my $cur_time = time();

	# check if we need to add an stock update
	# currently the ShowStock will add the task. We do this to make sure the graphic
	# will wait on the update. Perhaps later we could do extra checking on the kantelpunten
	# for this stock. Or perhaps we don't need this parameter at all.
	if (defined($param->{stock}) && !is_weekend() && is_inside_delayed_stock_hours())
	{
		my $stock = get_stock($param->{stock});
		if (defined($stock))
		{
			add_task(undef, 'intra', $stock->{id}, $stock->{stock}, $cur_time); 
		}
	}
		
	# Check for creating pending tasks
	if ($check_create_time <= $cur_time)
	{
		log_info("update: Check for new tasks", undef, 'updater');
	    my $sec = is_weekend() ? 28800 : (is_outside_stock_hours() ? (is_before_stock_hours() ? 1800 : 300) : 120);
		# create the news updateing task
		add_task(undef, 'news', 0, "sup0", $cur_time + $sec); 
	
    	if (is_inside_update_window())
    	{
	    	add_task(undef, 'quote', 0, undef, $cur_time);
    	}
    	if (is_after_stock_hours() && !is_weekend())
    	{
	    	# start update after 15 seconds if one already scheduled it will not overwrite
	    	add_task(undef, 'nintra', 0, undef, $cur_time+15);

	    	# create a task for clearing the cache if it does not exist yet, so no overwrite	
        	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time());
        	my $next_day = mktime(0, 0, 0, $mday, $mon, $year, 0, 0, $isdst) + ONE_DAY;
	   		add_task(undef, 'cache', 0, undef, $next_day);
	   		
	   		# create a task for creating the update email, if one already scheduled it will not overwrite
	   		# only create the task if in the future
	   		# there could be one problem if more kantelpunten are found after 18:30
	   		my $upd_time = mktime(0, 30, 18, $mday, $mon, $year, 0, 0, $isdst);
	   		add_task(undef, 'create_mails', 0, undef, $upd_time) if ($upd_time > $cur_time);
    	}
    	if (is_inside_delayed_stock_hours())
    	{
	    	add_task(undef, 'hit', 0, undef, $cur_time+300);
    	}
    	$check_create_time = $cur_time + 60;
	}
		
	# now do the real updating ...
	$file = get_next_todo();
	return if (!defined($file));	# nothing todo
	
	# we have something todo? Are we allowed as an handler??
	if (!start_handler())
	{
		log_info("updater: Had something todo but not allowed", undef, 'updater');
		return;
	}
	
	# ok we are allowed todo something
	# for now execute x tasks
	my $handle_max = 2;
	my $todo = $handle_max;
	my $task;
	my $executed = 0;
	while (defined($file) && ($todo > 0))
	{
		if ((-e $file) && 
		    defined($task = get_task($file)) &&
		    start_task($task) )
		{
			if (($task->{res} = execute_task($task)) < 0)
			{
				log_problem("updater: problem executing task '$task->{file}' err = $task->{res}");
				# What to do?  for now I'll just remove the task
			}
			finished_task($task);
		}
		else
		{
			# hmmm file does not exist could be possible if antoher took it
			log_handler("'$file' does not exist anymore, probably handled");
		}
		$todo--;
		$file = get_next_todo();
	}
	if (($todo == 0) && defined($file))
	{
		#we had more todo but not allowed
		log_handler("task '$file' pending but already done $handle_max");
	}
	
	stop_handler();
}

sub execute_task(@)
{
	my ($task) = @_;
	
	init_process();
	init_intraday();
	
	my $res = 0;
	if (is_task_type($task->{type}, 'intra'))
	{
		my $stock = get_stock($task->{stock});
		if (defined($stock))
		{
		    $res = update_cur_intraday(undef, $stock, undef, undef, undef, 30);
		    # TODO add some stuff for checking if we reached kantelpunten !!
		}
	}
	elsif (is_task_type($task->{type}, 'news'))
	{
	   	$res = news_update();	
	}
	elsif (is_task_type($task->{type}, 'quote'))
	{
		$res = update_quotes();
	}
	elsif (is_task_type($task->{type}, 'kantel'))
	{
    	my $stocks = read_stocks();
        $res = update_kantelpunten(undef, $stocks);
        if ($res > 0)
        {
	    	# we found kantelpunten schedule a task for updateing summary records
			add_task(undef, 'summary', 0, undef, time());
		}
	}
	elsif (is_task_type($task->{type}, 'summary'))
	{
		my $time = time();
		my $year = strftime("%Y", localtime($time));
		my $month = strftime("%m", localtime($time));
		my $day   = strftime("%j", localtime($time));
		$res  = make_sum_kantelpunten(1, $year);
		$res += make_sum_kantelpunten(1, $year, $month);
		$res += make_sum_kantelpunten(1, $year, undef, $day);
		$res += make_sum_porto("own", $year);
		$res += make_sum_porto("nl", $year);
		$res += make_sum_porto("be", $year);
	}
	elsif (is_task_type($task->{type}, 'nintra'))
	{
        my $stk = update_next_intraday();
        $stk = update_next_intraday() if (defined($stk) && ($stk ne ""));	# update another one
        if (defined($stk) && ($stk ne ""))
        {
	    	# start update after 15 seconds if one already scheduled it will not overwrite
	    	add_task(undef, 'nintra', 0, undef, time()+15, undef, 'nobusy');
	    	my $stock = get_stock($stk);
            $res = defined($stock) ? $stock->{id} : 9999;
        }
        elsif (defined($stk))
        {
	        # it is defined (so empty) mean we are finished, schedule a task for next day, update if existing
	        # we are forceing the update to make sure it is not anymore overwriten by other creations
            my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time());
            my $next_day = mktime(0, 0, 18, $mday, $mon, $year, 0, 0, $isdst) + ONE_DAY;
	    	add_task(undef, 'nintra', 0, undef, $next_day, 'force', 'nobusy');
            $res = 0;
    	}
    	else
    	{
	    	# just do nothing, we will not reschedule
    	}
	}
	elsif (is_task_type($task->{type}, 'cache'))
	{
		$res = clear_cache();
	}
	elsif (is_task_type($task->{type}, 'hit'))
	{
		$res = check_kantelpunten_hits();
	}
	elsif (is_task_type($task->{type}, 'create_mails'))
	{
		# currently we create all mails at the same time
		$res = make_kantelpunten_mails();
		if ($res > 0)
		{
			# ok we have created mails start the send_mails task
	    	add_task(undef, 'send_mails', 0, "0", time()+30);
    	}
	}
	elsif (is_task_type($task->{type}, 'send_mails'))
	{
		my $next = $task->{stock} + 1;
		# only send 75 mails at the same time
		$res = process_mails(75);
		if ($res > 0)
		{
			# we have tot do more create a new task in 10 seconds
	    	add_task(undef, 'send_mails', $next, "$next", time()+10);
    	}
    	elsif ($res <= -100)
    	{
	    	# oops this is bad, do not reschedule
			log_handler("send_mails failed with $res");
			log_problem("send_mails failed with $res");
    	}
    	elsif ($res < 0)
    	{
			# temporary error sending mails, try again in 1 minute
	    	add_task(undef, 'send_mails', $next, "$next", time()+60);
    	}
    	else
    	{
	    	# this is the zero case so we are finished, no reschedule
   		}
	}
	else
	{
		log_handler("Unknown task type $task->{type}");
		log_problem("execute_task: Unknown task type $task->{type}");
	}
	return $res;
}

# if we come her we basicaly are inside the update window as that is guaranteed by the schedular
sub update_quotes()
{

    my $p;    
    $p = 1;
    my $stocks = read_stocks();

    my $ret = update_cur_quotes(undef, $stocks);
    log_handler("update_quotes: returned $ret");
    if ((($ret < 0) && ($ret != -9)) || $test)
    {
	    # something went wrong try again in 5 minutes
		add_task(undef, 'quote', 0, undef, time() + 300, undef, 'nobusy');
    }                 
    if (($ret == 0) || $test)
    {
		# hmm no update but wanted try again within an hour
		add_task(undef, 'quote', 0, undef, time() + 3600, undef, 'nobusy');
    }       
    if (($ret > 0) || $test)
    {
	    # we found kantelpunten schedule a task for kantelpunten update
		add_task(undef, 'kantel', 0, undef, time());
    }
}

sub clear_cache(@)
{
    # this is a complete new day. we should do the follwing things:
    # 1) Delete (or store zipped) old intraday data (older 7 days)
    # 2) Delete all the cache pictures to be sure that new ones will be created
    my $dir = get_public_dir() . "php/cache";
  	my $d = IO::Dir->new($dir);
  	my $file;
  	my $deleted = 0;
   	if (defined $d) 
   	{
      	while (defined($file = $d->read))
       	{
       		next if ($file eq ".");
       		next if ($file eq "..");
        	unlink "$dir/$file";
        	$deleted++;
       	}
       	undef $d;
   	}
   	else
   	{
    	log_problem("cannot open cachedir '$dir'");
    	$deleted = -1;
	}
	# we could make a new task hover lets do it easy this time
	$deleted += clear_done_mails();
	return $deleted;
}

sub clear_done_mails(@)
{
    # Deletye the done mails to clean-up diskspace
    my $dir = get_private_dir() . "mailer/done";
  	my $d = IO::Dir->new($dir);
  	my $file;
  	my $deleted = 0;
   	if (defined $d) 
   	{
      	while (defined($file = $d->read))
       	{
       		next if ($file eq ".");
       		next if ($file eq "..");
        	unlink "$dir/$file";
        	$deleted++;
       	}
       	undef $d;
   	}
   	else
   	{
    	log_problem("cannot open mailed done dir '$dir'");
    	$deleted = -1;
	}
	return $deleted;
}

sub check_kantelpunten_hits(@)
{
	return 0;
	
	my $stocks = get_stocks();
}

