#################################################################################
# ===============================================================================
#            Copyright (C) 2001 GoldPocket Interactive, Inc.
#                      PROPRIETARY and CONFIDENTIAL
# ===============================================================================
# TBSAutoDemo.pl
#
# CREATION DATE
#   08-??-01
#	09-25-01 (modified) 
#
# ORIGINAL AUTHOR
#   Joseph Su, GoldPocket Interactive, Inc.
#   Markus Kangas, GoldPocket Interactive, Inc.
#
# DESCRIPTION
#   1. This program extracts certain input fields from the xml node, in the order of
#      their start times
#	2. Insert ATVEF triggers according to the start time, type, and id specified by 
#      the extracted fields
#
# REFERENCES
#
# NOTES/RESTRICTIONS
#
#################################################################################

require 5.003;

use XML::Parser;
use Win32::SerialPort qw( :STAT 0.19 );
use IO::Socket;


my(
	$POLL_RESULT_SLACK_TIME,    # Delay time from when the last poll message was sent
								# It defines the time (sec) needed to calculate 
								# poll results

	@ALLVALS,					# Array that holds time, type, and id information from 
								# the xml node

	@TIMEVALS,					# Array that holds time 
	@TYPEVALS,					# Array that holds type
	@IDVALS,					# Array that holds id
	$INPUT_FILE,				# File handle 
	$parser,					# Parser object used to parse xml node
	@factkeys,					# Array of hash keys that specifies the funfact node in xml
	@pollkeys,					# Array of hash keys that specifies the poll node in xml
	@triviakeys,				# Array of hash keys that specifies the trivia node in xml
	@leaderboardkeys,			# Array of hash keys that specifies the leaderboard node in xml
	@segmentkeys,				# Array of hash keys that specifies the segment trigger in xml
	@adjurykeys,				# Array of hash keys that specifies the adjury node in xml
			
	%currentAttrs,				# Hash table that holds all attributes at the current 
								# line of xml node

	@fields,					# Array of delimited time, type, and id pertaining 
	                            # to one object (i.e., funfact, leaderboard, etc)

	$begin_time,					# Start time of a trigger event
	$broadcaststring
);


##################################################################################
## Initialize all
##################################################################################
$broadcaststring = "Elimidate Deluxe Interactive";
$atvefURL = "http://eswebc.eventmatrix.com/10011/elimidate/index.asp";
$POLL_RESULT_SLACK_TIME = 7;
@ALLVALS = ();
@TIMEVALS = ();
@TYPEVALS = ();
@IDVALS = ();
@factkeys = ("factitemid", "starttime");
@pollkeys = ("pollitemid", "starttime", "type", "duration");
@triviakeys = ("trivia_bwitemid", "starttime", "type", "duration");
@leaderboardkeys = ("leaderboarditemid", "starttime");
@segmentkeys = ("timesegmentitemid", "starttime");
@adjurykeys = ("activeaditemid", "starttime");


##################################################################################
## Creating file handle and instantiate a XML parser object using XML::Parser (C-based)
##################################################################################
$INPUT_FILE = 'event.xml' || die "Can't find file \"$file\"";
    
$parser=new XML::Parser(Style=>'Stream');

$parser->parsefile($INPUT_FILE);        # Go ahead and call the setHandler routines
                                            # This will call StartTag, Text (not 
											# implemented here), and lastly EndTag

@ALLVALS = sort sort_by_number @ALLVALS;    # Sort by start time 

$count = @ALLVALS;

##################################################################################
## 1. Split each line using ":" as delimiter, and push each field into its 
##    corresponding name array
## 2. Debug print (time, type, and id arrays)
##################################################################################
my($i);
for ($i=0; $i<@ALLVALS; $i++) 
{
	@fields = split( /:/, @ALLVALS[$i] );
	push( @TIMEVALS, @fields[0] );
	push( @TYPEVALS, @fields[1] );
	push( @IDVALS, @fields[2] );

	#print  @ALLVALS[$i] . "\n";
	print @TIMEVALS[$i] . "\t" . @TYPEVALS[$i] . "\t" . @IDVALS[$i] . "\n";
}


##################################################################################
## Reverse the queues so that the first (earliest) trigger is on top, and will be
## popped off first 
##################################################################################
@TIMEVALS= reverse @TIMEVALS;
@TYPEVALS= reverse @TYPEVALS;
@IDVALS= reverse @IDVALS;


##################################################################################
## -----------------ATVEF trigger insertion starts here --------------------------                                 
##################################################################################

# $URL defines <-->
#$URL=$atvefURL;

# $EVENT_URL defines <-->
$EVENT_URL=$atvefURL;  #url for 10 second ping

# $FREQUENCY defines <--> 
$FREQUENCY=10;

# $START_OFFSET defines the offset from the script start time
$START_OFFSET=0;

# $PREFIX defines <-->
$PREFIX="tv"; #i.e. parent.bulkRequest(...



##################################################################################
## This code chunk defines all the message types for the output.txt
## file. The key is the message recieved from the output.txt file, and will
## be intepreted into the key-value as an ATVEF trigger later on
##################################################################################
%MessageTypes=();
$MessageTypes{'PollMessage'}="pollMessage";
$MessageTypes{'PollWithPoints'}="pollMessage";
$MessageTypes{'DelayedHybridPoll'}="pollMessage";
$MessageTypes{'PollResultsMessage'}="pollResults";
$MessageTypes{'PollResults'}="pollResults";
$MessageTypes{'PollWithPointsResults'}="pollResults";
$MessageTypes{'DelayedHybridPollResults'}="pollResults";

$MessageTypes{'LeaderBoardMessage'}="leaderBoard";
$MessageTypes{'Leaderboard'}="leaderBoard";

$MessageTypes{'QuestionResultsMessage'}="questionResultMessage";
$MessageTypes{'AnswerMessage'}="answerMessage";
$MessageTypes{'TextMessage'}="textMessage";
$MessageTypes{'EventTriggerMessage'}="eventTriggerMessage";
$MessageTypes{'AdJuryResultsMessage'}="adJuryResultsMessage";
$MessageTypes{'AdJuryMessage'}="adJuryMessage";
$MessageTypes{'DisplayAnswer'}="displayAnswer";
$MessageTypes{'IncrementPoints'}="incrementPoints";
$MessageTypes{'Answer'}="displayAnswer";
$MessageTypes{'QuestionMessage'}="questionMessage";
$MessageTypes{'Trivia'}="questionMessage";
$MessageTypes{'FunFact'}="textMessage";

$MessageTypes{'Sync'}="SYNC";

$MessageTypes{'DelayedHybridPollResults'}="delayedHybridPollResults";
$MessageTypes{'DelayedTriviaResults'}="delayedTriviaResults";
$MessageTypes{'RapidDelayedTrivia'}="questionMessage";


my $done = 0;
my $time = $TIMEVALS[0];

while($done==0) {
    $cnt++;        
    $time++;



   if($time % $FREQUENCY ==0) {
        $tmp="";
	for($a=0;$a<$tmp2;$a++) {
	    $tmp=$tmp." ";
        }
	$URL=$EVENT_URL."?$tmp2";
	$sendstring="<$URL>[n:${broadcaststring}$tmp][v:t]";
	$_=$sendstring;

	$nbytes=length($sendstring);
	$sum=0;
	for($count=0;$count<$nbytes;$count+=2) {
  	  $sum+=ord(substr($_,$count,1)) << 8;
  	  if($count!=$nbytes-1) 
	     {$sum+=ord(substr($_,$count+1,1));}
	  while($sum>=65536) {
             $sum-=65536;
             $sum+=1;
          }

        }
        $sum2=65535-$sum;
        $checksum=sprintf("\[%4X\]" ,$sum2);
	$checksum=~s/A-Z/a-z/g;
	$sendstring=$sendstring.$checksum;
	print "$time: $sendstring\n";
   }
   local($ok)=0;
   while($ok==0) {
     $val=pop(@TIMEVALS);
     if($val<=$time) {
        $time=$val;
        $type=pop(@TYPEVALS);
        $id=pop(@IDVALS);
	$sendstring="<$EVENT_URL>[v:1][s:bulkRequest('$MessageTypes{$type}',$id)]";
        if($MessageTypes{$type} eq "SYNC") {
 	     $sendstring="<>[gpi-changemode:$id]";
		$tmp2++; # increment the segment count used for announcement URLs
        }
	$_=$sendstring;

	$nbytes=length($sendstring);
	$sum=0;
	for($count=0;$count<$nbytes;$count+=2) {
  	  $sum+=ord(substr($_,$count,1)) << 8;
  	  if($count!=$nbytes-1) 
	     {$sum+=ord(substr($_,$count+1,1));}
	  while($sum>=65536) {
             $sum-=65536;
             $sum+=1;
          }

        }
        $sum2=65535-$sum;
        $checksum=sprintf("\[%4X\]" ,$sum2);
	$checksum=~s/A-Z/a-z/g;

	$sendstring=$sendstring.$checksum;
        print "$time: $sendstring\n";

     } else {push(@TIMEVALS,$val);$ok=1;}
     if(@TIMEVALS[0] eq "") {
 	$done=1;$ok=1;
	print "ALL Done\n";
     }
   }
   

}


##################################################################################
## ------------------------- End of Main -------------------------------------- ##
##################################################################################


##################################################################################
## ----------------------- Start of Subroutines ------------------------------- ##                                
##################################################################################

##################################################################################
## StartTag is called first when parser starts the parsing routine, i.e., when it
## encounters the start of a xml node (root tag)
#  
#---------------------------------------------------------------------------------
#                              Output Format
#---------------------------------------------------------------------------------
# PollMessage:
#		ID:				pollitemid
#		Type:			1
#       Result:			PollResults
#       Trigger time:	"starttime" + $POLL_RESULT_SLACK_TIME
#
# PollWithPoints
#		ID:				pollitemid
#		Type:			2
#       Result:			PollWithPointsResults
#       Trigger time:	"starttime" + $POLL_RESULT_SLACK_TIME
#
# DelayedPoll
#		ID:				pollitemid
#		Type:			3
#		Result:		    DelayedPollResults
#       Trigger time:	"starttime" + $POLL_RESULT_SLACK_TIME
#
# DelayedHybridPoll
#		ID:				pollitemid
#		Type:			4
#	    Result:			DelayedHybridPollResults
#       Trigger time:	"starttime" + $POLL_RESULT_SLACK_TIME
#---------------------------------------------------------------------------------
# Trivia
#		ID:				trivia_bwitemid
#		Type:			1
#	    Result:			TriviaResults
#       Trigger time:	"starttime" + "duration"
#
# DelayedTrivia
#		ID:				trivia_bwitemid
#		Type:			2
#	    Result:			DelayedTriviaResults
#       Trigger time:	"starttime" + "duration"
#
# RapidDelayedTrivia
#		ID:				trivia_bwitemid
#		Type:			3
#		Result:			RapidDelayedTriviaResults
#		Trigger time:	"starttime" + "duration"
#----------------------------------------------------------------------------------
# LeaderBoardMessage
#		ID:				leaderboarditemid      
#----------------------------------------------------------------------------------
# FunFact
#		ID:				factitemid      
#----------------------------------------------------------------------------------
# Sync
#		ID:				(timesegmentitemid+1)*10		
#----------------------------------------------------------------------------------
# AdJuryMessage
#		ID:				activeaditemid      
#----------------------------------------------------------------------------------
###################################################################################
sub StartTag {
	my ($expat,$eltype)=@_;
	#print "StartTag: $_ \n";
	
	%currentAttrs = %_;

	if ( $eltype eq 'factitem' )
    {

		push (@ALLVALS, GetStartTime($factkeys[1]) . ":" . "FunFact" . ":" . $currentAttrs{$factkeys[0]});		

	}
 	elsif ( $eltype eq 'pollitem' )
    {
		if ( $currentAttrs{$pollkeys[2]} == "1" )       # Type = 1 for regular poll
		{
			push (@ALLVALS, GetStartTime($pollkeys[1]) . ":" . "PollMessage" . ":" . $currentAttrs{$pollkeys[0]});		
			push (@ALLVALS, GetStartTime($pollkeys[1])+$currentAttrs{$pollkeys[3]}+$POLL_RESULT_SLACK_TIME . ":" . "PollResults" . ":" . $currentAttrs{$pollkeys[0]});	
		} 
		elsif ( $currentAttrs{$pollkeys[2]} == "2" )    # Type = 2 for poll with points
		{
			push (@ALLVALS, GetStartTime($pollkeys[1]) . ":" . "PollWithPoints" . ":" . $currentAttrs{$pollkeys[0]});		
			push (@ALLVALS, GetStartTime($pollkeys[1])+$currentAttrs{$pollkeys[3]}+$POLL_RESULT_SLACK_TIME . ":" . "PollWithPointsResults" . ":" . $currentAttrs{$pollkeys[0]});	
		} 
		elsif ( $currentAttrs{$pollkeys[2]} == "3" )    # Type = 3 for delayed poll
		{
			push (@ALLVALS, GetStartTime($pollkeys[1]) . ":" . "DelayedPoll" . ":" . $currentAttrs{$pollkeys[0]});		
			push (@ALLVALS, GetStartTime($pollkeys[1])+$currentAttrs{$pollkeys[3]}+$POLL_RESULT_SLACK_TIME . ":" . "DelayedPollResults" . ":" . $currentAttrs{$pollkeys[0]});	
		} 
		elsif ( $currentAttrs{$pollkeys[2]} == "4" )    # Type = 4 for delayed hybrid poll
		{
			push (@ALLVALS, GetStartTime($pollkeys[1]) . ":" . "DelayedHybridPoll" . ":" . $currentAttrs{$pollkeys[0]});		
			push (@ALLVALS, GetStartTime($pollkeys[1])+$currentAttrs{$pollkeys[3]}+$POLL_RESULT_SLACK_TIME . ":" . "DelayedHybridPollResults" . ":" . $currentAttrs{$pollkeys[0]});	
		}
		 
	}
 	elsif ( $eltype eq 'trivia_bwitem' )
    {		
		#print "trivia type = $currentAttrs{$triviakeys[2]} --------------------------------------- \n";

		if ( $currentAttrs{$triviakeys[2]} == "1" )      # Type = 1 for regular trivia
		{
			push (@ALLVALS, GetStartTime($triviakeys[1]) . ":" . "Trivia" . ":" . $currentAttrs{$triviakeys[0]});		
			push (@ALLVALS, GetStartTime($triviakeys[1])+$currentAttrs{$triviakeys[3]} . ":" . "TriviaResults" . ":" . $currentAttrs{$triviakeys[0]});		

		} 
		elsif ($currentAttrs{$triviakeys[2]} == "2")     # Type = 2 for delayed trivia
		{
			push (@ALLVALS, GetStartTime($triviakeys[1]) . ":" . "DelayedTrivia" . ":" . $currentAttrs{$triviakeys[0]});		
			push (@ALLVALS, GetStartTime($triviakeys[1])+$currentAttrs{$triviakeys[3]}. ":" . "DelayedTriviaResults" . ":" . $currentAttrs{$triviakeys[0]});		

		} 
		elsif ($currentAttrs{$triviakeys[2]} == "3")     # Type = 3 for rapidDelayedTrivia
		{
			push (@ALLVALS, GetStartTime($triviakeys[1]) . ":" . "RapidDelayedTrivia" . ":" . $currentAttrs{$triviakeys[0]});		
			push (@ALLVALS, GetStartTime($triviakeys[1])+$currentAttrs{$triviakeys[3]} . ":" . "RapidDelayedTriviaResults" . ":" . $currentAttrs{$triviakeys[0]});		
		}
	
	} 
	elsif ( $eltype eq 'leaderboarditem' )
    {
		push (@ALLVALS, GetStartTime($leaderboardkeys[1]) . ":" . "LeaderBoardMessage" . ":1");		
	}
	elsif ( $eltype eq 'timesegmentitem' )
    {
		push (@ALLVALS, GetStartTime($segmentkeys[1]) . ":" . "Sync" . ":" . ($currentAttrs{$segmentkeys[0]}+1)*10);		
	}
	elsif ( $eltype eq 'activeaditem' )
    {
		push (@ALLVALS, GetStartTime($adjurykeys[1]) . ":" . "AdJuryMessage" . ":" . $currentAttrs{$adjurykeys[0]});		
	}


}

##################################################################################
## EndTag is called after the parsing routine encounters the end of a xml node (root tag)
## Current this is not used, but can be further implemented depending on applications
##################################################################################
sub EndTag {
  my ($expat,$eltype)=@_;
  if ($eltype eq "root") {
    #print "END \n";
  }

}


##################################################################################
## Sorting an array by number (neither alphabetical nor ASCII-betical sort)
## This routine returns either 1 (a>b), 0 (a=b), or -1 (a<b)
##################################################################################
sub sort_by_number {
	$first = substr($a, 0, index($a, ":"));    #Get the first chunk of substring that ends in ":"
	$second = substr($b, 0, index($b, ":"));   #Get the second chunk of substring that ends in ":"
	if ($first > $second)
	{
		return 1;
	} elsif ($first < $second)
	{
		return -1;
	} else 
	{
		return 0;
	}
}


##################################################################################
# Parse the start time and convert everything to seconds
##################################################################################
sub GetStartTime
{
	#print "starttime: $currentAttrs{@_[0]} \n";		

	local $hour = substr($currentAttrs{@_[0]}, 0, 2);
	local $minute = substr($currentAttrs{@_[0]}, 3, 2);
	local $second = substr($currentAttrs{@_[0]}, 6, 2);
	$begin_time = $second + $minute*60 + $hour*3600;
	
	return $begin_time;
}