<?php

//
// Open Web Analytics - An Open Source Web Analytics Framework
//
// Copyright 2006 Peter Adams. All rights reserved.
//
// Licensed under GPL v2.0 http://www.gnu.org/copyleft/gpl.html
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// $Id$
//

if(!class_exists('owa_observer')) {
    require_once(OWA_DIR.'owa_observer.php');
}

/**
 * Conversion Event handlers
 * 
 * @author      Peter Adams <peter@openwebanalytics.com>
 * @copyright   Copyright &copy; 2006 Peter Adams <peter@openwebanalytics.com>
 * @license     http://www.gnu.org/copyleft/gpl.html GPL v2.0
 * @category    owa
 * @package     owa
 * @version        $Revision$
 * @since        owa 1.4.0
 */

class owa_conversionHandlers extends owa_observer {

    /**
     * Notify Event Handler
     *
     * @param     unknown_type $event
     * @access     public
     */
    function notify($event) {
    
        $update = false;

        $conversion_info = $this->checkForConversion( $event );

        // check for conversion
        if ( $conversion_info ) {

            // check for needed session_id
            if ( $event->get('session_id') ) {

                   // load session
                $s = owa_coreAPI::entityFactory('base.session');

                $s->load( $event->get( 'session_id' ) );

                // if session exists
                if ( $s->wasPersisted() ) {

                    //record conversion
                    if ( !empty( $conversion_info['conversion'] ) ) {
                        $goal_column = 'goal_'.$conversion_info['conversion'];
                        $already = $s->get( $goal_column );
                        // see if an existing value has been set goal value
                        $goal_value_column = 'goal_'.$conversion_info['conversion'].'_value';
                        $existing_value = $s->get( $goal_value_column );
                        $value = $conversion_info['value'];

                        // determin is we have a conversion event worth updating
                        // only record one goal of a particular type per session
                        if ( $already != true )    {
                            // there is a goal conversion
                            $s->set( $goal_column , true );
                            $update = true;
                            owa_coreAPI::debug( "$goal_column was achieved." );
                        } else {
                            // goal already happened but check to see if we need to add a value to it.
                            // happens in the case of ecommerce transaction where the value
                            // can come in a secondary request. if no value then return.
                            if ( ! $value ) {

                                owa_coreAPI::debug( 'Not updating session. Goal was already achieved and in same session.' );

                                return OWA_EHS_EVENT_HANDLED;
                            }
                        }

                        // Allow a value to be set if one has not be set already.
                        // this is needed to support dynamic values passed by commerce transaction events
                        if ( $value  && ! $existing_value )  {
                            $s->set( $goal_value_column, owa_lib::prepareCurrencyValue( $value ) );
                            $update = true;
                        }
                    }
                    //record goal start
                    if ( !empty($conversion_info['start'] ) ) {
                        $goal_start_column = 'goal_'.$conversion_info['start'].'_start';
                        $already_started = $s->get( $goal_start_column );

                        if ( $already_started != true ) {

                            $s->set( $goal_start_column, true );
                            $update = true;
                            owa_coreAPI::debug( "$goal_start_column was started." );

                        } else {
                            owa_coreAPI::debug( "$goal_start_column was already started." );
                        }
                    }

                    //update object
                    if ( $update ) {

                        // summarize goal conversions
                        $s->set('num_goals', $this->countGoalConversions($s));

                        // summarize goal conversion value
                        $s->set('goals_value', $this->sumGoalValues($s));

                        // summarize goal starts
                        $s->set('num_goal_starts', $this->countGoalStarts($s));

                        $ret = $s->update();
                        if ( $ret ) {
                            // create a new_conversion event so that the total conversion
                            // metrics can be resummarized
                            $this->dispatchNewConversionEvent($event);

                            return OWA_EHS_EVENT_HANDLED;
                        } else {

                            return OWA_EHS_EVENT_FAILED;
                        }

                    } else {
                        owa_coreAPI::debug( "nothing about this conversion is worth updating." );

                        return OWA_EHS_EVENT_HANDLED;
                    }

                } else {
                    owa_coreAPI::debug("Conversion processing aborted. No session could be found.");

                    return OWA_EHS_EVENT_FAILED;
                }

            } else {

                owa_coreAPI::notice('Not persisting conversion. Session id missing from event.');

                return OWA_EHS_EVENT_HANDLED;
            }

        } else {
            owa_coreAPI::debug('No goal start or conversion detected.');

            return OWA_EHS_EVENT_HANDLED;
        }
    }
    
    // create a new_conversion event so that the total conversion
    // metrics can be resummarized
    function dispatchNewConversionEvent($event) {
    
        $dispatch = owa_coreAPI::getEventDispatch();
        $ce = $dispatch->makeEvent( 'new_conversion' );
        $ce->set( 'session_id', $event->get( 'session_id' ) );
        $dispatch->asyncNotify( $ce );
    }
        
    function checkForConversion($event) {
    
        $goal_info = array('conversion' => '', 'value' => '', 'start' => '');
        $siteId = $event->get('siteId');

        if ( ! $siteId ) {
            $siteId = $event->get('site_id');
        }

        $gm = owa_coreAPI::supportClassFactory('base', 'goalManager', $siteId);
        $goals = $gm->getActiveGoals();
        owa_coreAPI::debug('active goals: '.print_r($goals, true));
        if (empty($goals)) {
            return;
        }

        $is_match = false;

        $start = '';

        foreach ($goals as $num => $goal) {

            if (!empty($goal)) {

                if (array_key_exists('goal_status', $goal) && $goal['goal_status'] === 'active') {
                    switch ($goal['goal_type']) {

                        case 'url_destination':

                            $match = $this->checkUrlDestinationGoal($event, $goal);
                            $start = $this->checkGoalStart($event, $goal);
                            break;

                        case 'pages_per_visit':

                            $match = $this->checkPagesPerVisitGoal($event, $goal);
                            break;

                        case 'visit_duration':

                            $match = $this->checkPagesPerVisitGoal($event, $goal);
                            break;
                    }

                    if ($match) {
                        $goal_info['conversion'] = $match;
                    }

                    if ($start) {
                        $goal_info['start'] = $start;
                    }

                    //check for dynamic value from commerce transaction

                    if ($event->get('ct_total')) {
                        $goal_value =  $event->get('ct_total');
                    } else {
                        // else just use the static value if one is set.
                        if ( array_key_exists('goal_value', $goal) ) {
                            $goal_value = $goal['goal_value'];
                        }
                    }

                    $goal_info['value'] = $goal_value;
                } else {
                    owa_coreAPI::debug("Goal $num not active.");
                }
            }
        }
        owa_coreAPI::debug('conversion info: '.print_r($goal_info, true));
        return $goal_info;
    }
    
    function checkPagesPerVisitGoal($event, $goal) {

        $num = $event->get('npvs');

        if ($num) {
            $operator = $goal['details']['operator'];
            $req = $goal['details']['num_pageviews'];

            switch ($operator) {

                case '=':
                     if ($num === $req) {
                         return $goal['goal_number'];
                     }

                case '<':
                    if ($num < $req) {
                         return $goal['goal_number'];
                     }

                case '>':
                    if ($num > $req) {
                         return $goal['goal_number'];
                     }
            }
        }
        return false;
    }
    
    function checkVisitDurationGoal($event, $goal) {

        $num = $event->get('session_duration');
        $operator = $goal['details']['operator'];
        $req = $goal['details']['duration'];

        switch ($operator) {

            case '=':
                 if ($num === $req) {
                     return $goal['goal_number'];
                 }

            case '<':
                if ($num < $req) {
                     return $goal['goal_number'];
                 }

            case '>':
                if ($num > $req) {
                     return $goal['goal_number'];
                 }
        }

        return false;
    }
    
    function checkUrlDestinationGoal($event, $goal) {
        $match = '';
        $page_uri = $event->get('page_uri');

        switch ($goal['details']['match_type']) {

            case 'exact':

                if ( $page_uri === $goal['details']['goal_url'] ) {
                    $match = $goal['goal_number'];
                }
                break;

            case 'begins':

                $length = strlen( $goal['details']['goal_url'] );
                $check = strpos( $page_uri, $goal['details']['goal_url']);
                if ( $check === 0 ) {
                    $match = $goal['goal_number'];
                }
                break;

            case 'regex':

                $pattern = sprintf('@%s@i', $goal['details']['goal_url']);
                $check = preg_match( $pattern, $page_uri );
                if ( $check > 0 ) {
                    $match = $goal['goal_number'];
                }
                break;
        }

        return $match;
    }
    
    function checkGoalStart($event, $goal) {
        $page_uri = $event->get('page_uri');
        // check for goal start
        if ( array_key_exists( 'funnel_steps', $goal['details'] ) ) {
            // check the first step
            $step = $goal['details']['funnel_steps'][1];
            $pattern = sprintf('@%s@i', $step['url']);
            $check = preg_match($pattern, $page_uri );
            if ($check > 0) {
                return $goal['goal_number'];
            }
        }
    }
    
    function countGoalConversions($session) {

        $num = owa_coreAPI::getSetting('base', 'numGoals');
        $count = 0;
        for ($i = 0;$i < $num;$i++) {
            $col_name = 'goal_'.$i;
            $count = $count + $session->get($col_name);

        }
        owa_coreAPI::debug('session total goal count: '.$count);
        return $count;
    }

    function countGoalStarts($session) {

        $num = owa_coreAPI::getSetting('base', 'numGoals');
        $count = 0;
        for ($i = 0;$i < $num;$i++) {
            $col_name = 'goal_'.$i.'_start';
            $count = $count + $session->get($col_name);
        }
        owa_coreAPI::debug('session total goal starts: '.$count);
        return $count;
    }
    
    function sumGoalValues($session) {

        $num = owa_coreAPI::getSetting('base', 'numGoals');
        $sum = 0;
        for ($i = 0;$i < $num;$i++) {
            $col_name = 'goal_'.$i.'_value';
            $sum = $sum + $session->get($col_name);
        }
        owa_coreAPI::debug('session total goal value: '.$sum);
        return $sum;
    }
}

?>