package Opals::SIF::SifSubscriber;

# Version number
$VERSION   = 0.01;


use warnings;
use strict;
use XML::XPath;
use XML::LibXML;
use Opals::SIF::SIF_MsgFactory;
use Opals::SIF::HTTPService;
use Opals::SIF::AckRegisterMsgHandler;
use Opals::SIF::Specs;
use Opals::SIF::ObjectDataParser::StudentPersonalParser;



my $sifMsgFatory= Opals::SIF::SIF_MsgFactory->new();
my $httpSvc = Opals::SIF::HTTPService->new();
my $stdInfoParser=Opals::SIF::ObjectDataParser::StudentPersonalParser->new();

sub new {
    my ($class,$sifInfo,$zone) = @_;
    my $self={
            sifInfo=>$sifInfo,
            zone=>$zone,
            regiestered=>0,
            subscribeTo=>undef
        };
    bless $self, $class;
    return $self;
}

#################################################################

sub init{
    my ($self)=@_;
    my $ret=0;
    if($self->register() && defined $self->{"acl"}->{'SIF_Subscribe'}){
        if($self->subscribe()){
            $ret=1;
        }
    }
    my $msg =$sifMsgFatory->createMessage($self->{'sifInfo'},"SIF_Request","StudentPersonal");
    $httpSvc->post($self->{'zone'},$msg->getXml());

    return $ret;
}
#################################################################
sub register{
    my($self)=@_;
    my $regMsg =$sifMsgFatory->createMessage($self->{'sifInfo'},"SIF_Register");
    my $ackMsg= $httpSvc->post($self->{'zone'},$regMsg->getXml());
    my $rs =processAckMsg($ackMsg);
    my $success=1;
    if($rs->{'status'} eq "0"){
        $self->{"registered"}=1;
        $self->{"acl"}=getAcl($ackMsg);
    }
    else{
        $success=0;
        #log register error
    }
    return $success;

}
#################################################################
sub unRegister{
    my($self,$zone)=@_;
    my $msg =$sifMsgFatory->createMessage($self->{'sifInfo'},"SIF_UnRegister");
    my $rs= $httpSvc->post($self->{'zone'},$msg->getXml());

}

#################################################################
sub subscribe{
    my($self)=@_;
    my $msg =$sifMsgFatory->createMessage($self->{'sifInfo'},"SIF_Subscribe");
    my $ackMsg= $httpSvc->post($self->{'zone'},$msg->getXml());
    my $rs =processAckMsg($ackMsg);
    if($rs->{'status'} eq "0"){
        $self->{"subscribed"}=1;;
    }


}
#################################################################
sub unSubscribe{
    my($self,$zone)=@_;
    my $regMsg =$sifMsgFatory->createMessage($self->{'sifInfo'},"SIF_Unsubscribe");
    my $ackMsg= $httpSvc->post($self->{'zone'},$regMsg->getXml());

}
#################################################################
sub requestMessage{
    my($self)=@_;
    my $regMsg =$sifMsgFatory->createMessage($self->{'sifInfo'},"SIF_Request");
    my $rs= $httpSvc->post($self->{'zone'},$regMsg->getXml());

}

#################################################################
sub getMessage{
    my($self,$zone)=@_;
    my $msg =$sifMsgFatory->createMessage($self->{'sifInfo'},"SIF_GetMessage");
    my $ackMsg= $httpSvc->post($self->{'zone'},$msg->getXml());
    my $rs =processAckMsg($ackMsg);
    if($rs->{'status'} eq "0"){
        print "processing ....\n";
        my $xmlObj =XML::XPath->new(xml=>$ackMsg);
        my ($xml)=$xmlObj->findnodes_as_string(XPATH_GET_MSG);
        $self->handleGetMsg($xml);

    }
}

#################################################################
sub isRegistered{
    my($self)=@_;
    return $self->{'registered'};
}
#################################################################
sub hasAccess{
    my($self,$access,$dataObjName)=@_;
    return $self->{'acl'}->{$dataObjName}->{"SIF_SubscribeAccess"};
}

#################################################################
#
# Reference http://specification.sifinfo.org/Implementation/2.4/Messaging.html#AgentMessageHandlingProtocols
#
sub handleGetMsg{
    my ($self,$xml)=@_;
    my $sifErr=undef;
    my $ackInfo={};
    my $parser   = XML::LibXML->new();
    eval { $parser->parse_string($xml); };
    if($@){
        # STEP 2: XML not well-formed  
        $sifErr={SIF_Cateogry=>1,SIF_Code=>2};
    }

    else{
         my $xmlObj =XML::XPath->new(xml=>$xml);
         my $version="1.1";
         if($xml =~ m/<SIF_MsgId>(.*?)<\/SIF_MsgId>/g){
            $ackInfo->{'originalMsgId'}=$1;
         }
         if($xml =~ m/<SIF_SourceId>(.*?)<\/SIF_SourceId>/g){
            $ackInfo->{'originalSourceId'}=$1;
         }

         if(my ($node) =$xmlObj->findnodes("/SIF_Message")){
             $version=$node->getAttribute("Version");
         }
        # STEP 5: check if SIF version supported
         if(!defined SIF_SUPPORT_VERSION->{$version}){
            # STEP 6: not supported
            $sifErr={SIF_Cateogry=>12,SIF_Code=>3};
         }
         elsif(!validateXmlMsg($xml)){ #STEP 7
            #STEP 8
            $sifErr={SIF_Cateogry=>1,SIF_Code=>3};
         }
        # STEP 9
         elsif(!$xmlObj->exists("/SIF_Message/SIF_Event") &&
               !$xmlObj->exists("/SIF_Message/SIF_Response")){
            #STEP 10
            $sifErr={SIF_Cateogry=>12,SIF_Code=>2};
         }
         else{
            # STEP 11: Handling Event/Response message
            my $xPath="";
            if($xmlObj->exists("/SIF_Message/SIF_Event")){
                my ($eventXml)=$xmlObj->findnodes_as_string(XPATH_EVENT_OBJECT);
                processEvent($eventXml);
            }
            elsif($xmlObj->exists("/SIF_Message/SIF_Response")){
                my ($objXml)=$xmlObj->findnodes_as_string(XPATH_RESPONSE_OBJECT);

                processResponse($objXml);

            }
            #my $stdInfo=$stdInfoParser->parse($stdObjXml,$version);
            $ackInfo->{'SIF_Code'}=1;
         }
         if(defined $sifErr){
            $ackInfo->{'error'}=$sifErr;
         }
         my $ackMsg =$sifMsgFatory->createMessage($self->{'sifInfo'},"SIF_Ack",$ackInfo);
         my $zisAckMsg= $httpSvc->post($self->{'zone'},$ackMsg->getXml());

    }
}
#################################################################
sub processEvent{
    my ($xml)=@_;
    my $xmlObj =XML::XPath->new(xml=>$xml);
    my ($node) =$xmlObj->findnodes("/SIF_ObjectData/SIF_EventObject[\@ObjectName='StudentPersonal']");
    my $action= $node->getAttribute("Action");
    my ($stdXml)=$xmlObj->findnodes_as_string("/SIF_ObjectData/SIF_EventObject/StudentPersonal");
    my $stdInfo=$stdInfoParser->parse($stdXml,"2.4");
    print "$action\n\n";
    foreach my $fname(keys %$stdInfo){
        print "\t$fname:" , $stdInfo->{$fname},"\n";
    }


}

#################################################################
sub processResponse{
    my ($xml)=@_;
    my $xmlObj =XML::XPath->new(xml=>$xml);
    my @stdNodes =$xmlObj->findnodes("/SIF_Response/SIF_ObjectData/StudentPersonal");
    foreach my $node(@stdNodes){
        my $stdInfo =$stdInfoParser->parse($node->toString(),"2.4");
         foreach my $fname(keys %$stdInfo){
            print "\t$fname:" , $stdInfo->{$fname},"\n";
        }
    }


}
#################################################################
sub validateXmlMsg{
    my ($xml)=@_;
#to be implimented
#REF:http://specification.sifinfo.org/Implementation/2.4/CodeSets.html#InfrastructureErrorCategoryType
    return 1;
}
#################################################################

sub processAckMsg{
    my ($xmlMsg)=@_;
    my $parser   = XML::LibXML->new();
    eval { $parser->parse_string($xmlMsg); };
    my $rs={};
    if($@){
        $rs = {status=>0, error=>{desc=>"Invalid XML"}};
    }
    else{
        my $xmlObj =XML::XPath->new(xml=>$xmlMsg);
        if($xmlObj->exists(XPATH_ACK_ERROR)){
            my $error={code     =>$xmlObj->getNodeText(XPATH_ACK_ERROR_CODE),
                        category=>$xmlObj->getNodeText(XPATH_ACK_ERROR_CATEGORY),
                        desc    =>$xmlObj->getNodeText(XPATH_ACK_ERROR_DESC),
                        extDesc =>$xmlObj->getNodeText(XPATH_ACK_ERROR_EXTENDEDDESC)
                        };
            $rs = {status=>-1, error=>$error};

        }
        elsif($xmlObj->exists(XPATH_ACK_STATUS_CODE)){
            my $code=$xmlObj->getNodeText(XPATH_ACK_STATUS_CODE);
            $rs->{'status'} =$code;
            if ($code eq "0" || $code eq "0"){
                $rs->{'error'}=undef;
            }
            elsif($code eq "7"){
                $rs->{'error'}={desc=>"duplicate SIF_MsgId"};
            }
            elsif($code eq "8"){
                 $rs->{'error'}={desc=>"ZIS is asleep"};

            }
            else{
                $rs->{'error'}={desc=>"UNKNOW ERROR"};
            }

        }
        else{
            $rs = {status=>-1, error=>{desc=>"UNKNOW ERROR"}};
        }

    }
        
    return $rs;
   
}
############################################################################################
sub getAcl{
    my ($xmlMsg) =@_;

    my @accessCtrl= qw(
    SIF_ProvideAccess
    SIF_SubscribeAccess 
    SIF_PublishAddAccess 
    SIF_PublishChangeAccess
    SIF_PublishDeleteAccess
    SIF_RequestAccess
    SIF_RespondAccess);

    my $acl={}; 
    my $xpath= XPATH_ACK_STATUS_DATA ."/SIF_AgentACL" ;
    my $xmlObj =XML::XPath->new(xml=>$xmlMsg);

    if($xmlObj->exists($xpath)){
       foreach my $ac (@accessCtrl){
           if(my ($node)=$xmlObj->findnodes("$xpath/$ac/SIF_Object")){
                my $objName= $node->getAttribute("ObjectName"); 
                $acl->{$ac}->{$objName}=1;
            }
       }
    }
    return $acl;

}


#################################################################
1;

