<?php
/********************************************************************************
 * (c)1337 aheadware.com - All rights reserved
 ********************************************************************************/


class TB_Server_Control_Appointment {

    const ATTENDANCE_STATUS_TIME_LIMIT = 0; //86400; // 24h in Sekunden

    /**
     * @param TB_Server_Core_RequestData $params
     *
     * @return TB_Server_Core_Response
     */
    public static function create( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $profile = TB_Server_Core_Session::get()->getProfile();
        if ( !$profile->isTrainer() && !$profile->isCoTrainer() ) {
            throw new Exception( 'No rights' );
        }

        // Validity check
        if ( $params->get( 'starttime' ) < time() ) {
            throw new Exception( 'Cannot create an appointment in the past.' );
        }

        // If is it a seral appointment
        $isSerial = ( "serial" == $params->get( 'frequency' ) );
        if ( $isSerial ) {

            // Validate additional params
            $freqSpan = _xss( $params->get( 'frequency-span' ) );
            $freqCount = (int)$params->get( 'frequency-count' );
            $startDate = date( (int)$params->get( 'starttime' ) );
            $freqSpanAdder = NULL;

            switch( $freqSpan ) {
                case 'daily':
                    $freqSpanAdder = "day";
                    break;

                case 'weekly':
                    $freqSpanAdder = "week";
                    break;

                case 'monthly':
                    $freqSpanAdder = "month";
                    break;

                case 'annually':
                    $freqSpanAdder = "year";
                    break;

                default:
                    throw new Exception( "Invalid frequency span value: " . $freqSpan );
            }

            if ( $freqCount < 1 || 13 < $freqCount ) {
                throw new Exception( "Invalid frequency count value: " . $freqCount );
            }

            $appointment = new TB_Shared_Ent_TeamData_Appointment();
            $appointment->team_id = TB_Server_Core_Session::get()->getTeam()->id;
            $appointment->subject = _xss( $params->get( 'subject' ) );
            $appointment->home = _xss( $params->get( 'home' ) );
            $appointment->guest = _xss( $params->get( 'guest' ) );
            $appointment->id_nr = _xss( $params->get( 'id_nr' ) );
            $appointment->home_score = _xss( $params->get( 'home_score' ) );
            $appointment->guest_score = _xss( $params->get( 'guest_score' ) );
            $appointment->starttime = _xss( $params->get( 'starttime' ) );

            if ( TB_Server_Core_Session::get()->isPremium() )
            {
                $appointment->feedback_deadline = _xss( $params->get( 'feedback_deadline', 0 ) );
                $appointment->feedback_deadline_notice = _xss( $params->get( 'feedback_deadline_notice' ) );
            }
            else
            {
                $appointment->feedback_deadline = 0;
                $appointment->feedback_deadline_notice = NULL;
            }

            if ( is_null( $appointment->feedback_deadline ) )
            {
                $appointment->feedback_deadline = 0;
            }

            // This is set to avoid triggering the event system - will be updated few lines below
            $appointment->serial_id = 0;
            $appointment->duration = _xss( $params->get( 'duration' ) );
            $appointment->location = _xss( $params->get( 'location' ) );
            $appointment->comment = _xss( $params->get( 'comment' ) );
            $appointment->save();

            // Set correct serial id
            $appointment->serial_id = $appointment->id;
            $appointment->save();

            // Repeat x-times
            for( $fcnt = 0; $fcnt < $freqCount; $fcnt++ ) {

                $appointment->id = NULL;
                $appointment->starttime = strtotime(date("Y-m-d H:i", $startDate) . " +" . (1+$fcnt) . " " . $freqSpanAdder );
                $appointment->save();

            }

        } else {
            $appointment = new TB_Shared_Ent_TeamData_Appointment();
            $appointment->team_id = TB_Server_Core_Session::get()->getTeam()->id;
            $appointment->subject = _xss( $params->get( 'subject' ) );
            $appointment->home = _xss( $params->get( 'home' ) );
            $appointment->guest = _xss( $params->get( 'guest' ) );
            $appointment->id_nr = _xss( $params->get( 'id_nr' ) );
            $appointment->home_score = _xss( $params->get( 'home_score' ) );
            $appointment->guest_score = _xss( $params->get( 'guest_score' ) );
            $appointment->starttime = _xss( $params->get( 'starttime' ) );
            if ( TB_Server_Core_Session::get()->isPremium() )
            {
                $appointment->feedback_deadline = _xss( $params->get( 'feedback_deadline', 0 ) );
                $appointment->feedback_deadline_notice = _xss( $params->get( 'feedback_deadline_notice' ) );
            }
            else
            {
                $appointment->feedback_deadline = 0;
                $appointment->feedback_deadline_notice = NULL;
            }

            if ( is_null( $appointment->feedback_deadline ) )
            {
                $appointment->feedback_deadline = 0;
            }

            $appointment->duration = _xss( $params->get( 'duration' ) );
            $appointment->location = _xss( $params->get( 'location' ) );
            $appointment->comment = _xss( $params->get( 'comment' ) );
            $appointment->save();
        }


        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     */
    public static function subscribe( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $resp->addData( 'team', TB_Shared_Ent_TeamData_Team::get( TB_Server_Core_Session::get()->getTeam()->id ) );

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     *
     * @return TB_Server_Core_Response
     */
    public static function createSerial( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $profile = TB_Server_Core_Session::get()->getProfile();
        if ( !$profile->isTrainer() && !$profile->isCoTrainer() ) {
            throw new Exception( 'No rights' );
        }

        // Validity check
        if ( $params->get( 'starttime' ) < time() ) {
            throw new Exception( 'Cannot create an appointment in the past.' );
        }

        // If is it a seral appointment
        $isSerial = ( "serial" == $params->get( 'frequency' ) );
        if ( $isSerial ) {

            // Validate additional params
            $freqSpan = _xss( $params->get( 'frequency-span' ) );
            $freqCount = (int)$params->get( 'frequency-count' );
            $startDate = date( (int)$params->get( 'starttime' ) );
            $freqSpanAdder = NULL;

            switch( $freqSpan ) {
                case 'daily':
                    $freqSpanAdder = "day";
                    break;

                case 'weekly':
                    $freqSpanAdder = "week";
                    break;

                case 'monthly':
                    $freqSpanAdder = "month";
                    break;

                case 'annually':
                    $freqSpanAdder = "year";
                    break;

                default:
                    throw new Exception( "Invalid frequency span value: " . $freqSpan );
            }

            if ( $freqCount < 1 || 13 < $freqCount ) {
                throw new Exception( "Invalid frequency count value: " . $freqCount );
            }

            $appointment = new TB_Shared_Ent_TeamData_Appointment();
            $appointment->team_id = TB_Server_Core_Session::get()->getTeam()->id;
            $appointment->subject = _xss( $params->get( 'subject' ) );
            $appointment->home = _xss( $params->get( 'home' ) );
            $appointment->guest = _xss( $params->get( 'guest' ) );
            $appointment->id_nr = _xss( $params->get( 'id_nr' ) );
            $appointment->home_score = _xss( $params->get( 'home_score' ) );
            $appointment->guest_score = _xss( $params->get( 'guest_score' ) );
            $appointment->starttime = _xss( $params->get( 'starttime' ) );

            if ( TB_Server_Core_Session::get()->isPremium() )
            {
                $appointment->feedback_deadline = _xss( $params->get( 'feedback_deadline', 0 ) );
                $appointment->feedback_deadline_notice = _xss( $params->get( 'feedback_deadline_notice' ) );
            }
            else
            {
                $appointment->feedback_deadline = 0;
                $appointment->feedback_deadline_notice = NULL;
            }

            if ( is_null( $appointment->feedback_deadline ) )
            {
                $appointment->feedback_deadline = 0;
            }

            // This is set to avoid triggering the event system - will be updated few lines below
            $appointment->serial_id = 0;
            $appointment->duration = _xss( $params->get( 'duration' ) );
            $appointment->location = _xss( $params->get( 'location' ) );
            $appointment->comment = _xss( $params->get( 'comment' ) );
            $appointment->save();

            // Set correct serial id
            $appointment->serial_id = $appointment->id;
            $appointment->save();

            // Repeat x-times
            for( $fcnt = 0; $fcnt < $freqCount; $fcnt++ ) {

                $appointment->id = NULL;
                $appointment->starttime = strtotime(date("Y-m-d H:i", $startDate) . " +" . (1+$fcnt) . " " . $freqSpanAdder );
                $appointment->save();

            }

        } else {

            throw new Exception( "Not a serial appointment" );

        }

        return $resp;
    }

    /**
     * Updates existing appointment
     *
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     * @throws Exception
     */
    public static function update( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $db = TB_Shared_Db_TeamData::get();

        try {
            $db->beginTransaction();

            // Rights check
            $profile = TB_Server_Core_Session::get()->getProfile();
            $appointment = NULL;
            if ( $profile->isTrainer() || $profile->isCoTrainer() ) {
                /** @var TB_Shared_Ent_TeamData_Appointment $appointment */
                $appointment = TB_Shared_Ent_TeamData_Appointment::get( $params->get( 'id', 0 ) );
                if ( !isset( $appointment ) || $appointment->team_id != $profile->team_id ) {
                    throw new Exception( 'Invalid appointment to update.' );
                }
                // Validity check
                if ( $appointment->starttime != $params->get( 'starttime' ) && $params->get( 'starttime' ) < time() ) {
                    throw new Exception( 'Cannot set starttime into the past.' );
                }


            } else {
                throw new Exception( 'No rights' );
            }

            $appointment->subject = _xss( $params->get( 'subject' ) );
            $appointment->home = _xss( $params->get( 'home' ) );
            $appointment->guest = _xss( $params->get( 'guest' ) );
            $appointment->id_nr = _xss( $params->get( 'id_nr' ) );
            $appointment->home_score = _xss( $params->get( 'home_score' ) );
            $appointment->guest_score = _xss( $params->get( 'guest_score' ) );
            if ( !is_null( $params->get( 'starttime' ) ) ) {
                $appointment->starttime = _xss( $params->get( 'starttime' ) );
            }

            if ( TB_Server_Core_Session::get()->isPremium() )
            {
                $appointment->feedback_deadline = _xss( $params->get( 'feedback_deadline', 0 ) );
                $appointment->feedback_deadline_notice = _xss( $params->get( 'feedback_deadline_notice' ) );
            }
            else
            {
                $appointment->feedback_deadline = 0;
                $appointment->feedback_deadline_notice = NULL;
            }

            if ( is_null( $appointment->feedback_deadline ) )
            {
                $appointment->feedback_deadline = 0;
            }

            $appointment->duration = _xss( $params->get( 'duration' ) );
            $appointment->location = _xss( $params->get( 'location' ) );
            $appointment->comment = _xss( $params->get( 'comment' ) );


            // Should we reset attendee list for this appointment
            $resetAttendees = $params->get( 'reset-attendees');
            if ( isset( $resetAttendees ) && 'reset' == $resetAttendees ) {

                // Delete all attendees
                TB_Shared_Ent_TeamData_Attendee::deleteAllForAppointmentId( $appointment->id );

            }
            
            $appointment->save();

            $db->commit();

        } catch ( Exception $e ) {
            $db->rollBack();
        }

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     *
     * @return TB_Server_Core_Response
     */
    public static function delete( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        // Rights check
        $profile = TB_Server_Core_Session::get()->getProfile();
        $appointment = NULL;
        if ( $profile->isTrainer() || $profile->isCoTrainer() ) {
            /** @var TB_Shared_Ent_TeamData_Appointment $appointment */
            $appointment = TB_Shared_Ent_TeamData_Appointment::get( $params->get( 'appointment_id', 0 ) );
            if ( !isset( $appointment ) || $appointment->team_id != $profile->team_id ) {
                throw new Exception( 'Invalid appointment to update.' );
            }

            // Delete appointment and all its relations
            $appointment->delete();
        }


        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     *
     * @return TB_Server_Core_Response
     */
    public static function getReminder( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $profile = TB_Server_Core_Session::get()->getProfile();

        /** @var TB_Shared_Ent_TeamData_Appointment $appointment */
        $appointment = TB_Shared_Ent_TeamData_Appointment::get( $params->get( 'appointment_id' ) );
        $attendees = TB_Shared_Ent_TeamData_Attendee::getByAppointmentId( $appointment->id );
        $profiles = TB_Shared_Ent_TeamData_Profile::getProfilesByTeamId( $profile->team_id );
        $tpl = new TB_Server_Utils_Template( 'mail/appointmentreminder' );
        $mailTxt = $tpl->get( array(
            'appointment_name' => $appointment->getName(),
            'appointment_date' => TB_Server_Utils_Helper::getDate( $appointment->starttime ),
            'appointment_time' => TB_Server_Utils_Helper::getTime( $appointment->starttime )
        ));
        $resp->addData( 'mailtext', $mailTxt );
        $resp->addData( 'appointment', $appointment );
        $resp->addData( 'attendees', $attendees );
        $resp->addData( 'profiles', $profiles );

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     */
    public static function sendReminder( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $profile = TB_Server_Core_Session::get()->getProfile();
        if ( !$profile->isTrainer() && !$profile->isCoTrainer() ) {
            throw new Exception( 'No rights' );
        }

        /** @var TB_Shared_Ent_TeamData_Appointment $appointment */
        $appointment = TB_Shared_Ent_TeamData_Appointment::get( $params->get( 'appointment_id' ) );
        if ( !isset( $appointment ) || $profile->team_id != $appointment->team_id ) {
            throw new Exception( 'Invalid appointment' );
        }

        $team = TB_Server_Core_Session::get()->getTeam();
        if ( !isset( $team ) ) {
            throw new Exception( 'No team found.' );
        }

        $tpl = new TB_Server_Utils_Template( 'mail/appointmentreminder2' );
        $content = $tpl->get( array(
            'appointment_name' => $appointment->getName(),
            'appointment_date' => TB_Server_Utils_Helper::getDate( $appointment->starttime ),
            'appointment_time' => TB_Server_Utils_Helper::getTime( $appointment->starttime ),
            'team_display_name' => $team->display_name,
            'appointment_url' => 'http://client.tbuddy.de/#/c=Appointment&a=index'
        ));


        $profiles = TB_Shared_Ent_TeamData_Profile::getProfilesByTeamId( $appointment->team_id );
        $attendees = TB_Shared_Ent_TeamData_Attendee::getByAppointmentId( $appointment->id );

        /** @var TB_Shared_Ent_TeamData_Profile $p */
        foreach( $profiles as $p ) {
            $hasSetStatus = false;
            /** @var TB_Shared_Ent_TeamData_Attendee $a */
            foreach( $attendees as $a ) {
                if ( $a->profile_id == $p->id ) {
                    $hasSetStatus = true;
                    break;
                }
            }
            if ( !$hasSetStatus ) {
                $mailN = new TB_Shared_Ent_Core_EmailNotification();
                $mailN->sender_profile_id = $profile->id;
                $mailN->receiver_type = TB_Shared_Ent_Core_EmailNotification::RECEIVER_TYPE_PROFILE;
                $mailN->receiver_id = $p->id;
                $mailN->subject = 'TBuddy - Terminerinnerung';
                $mailN->content = $content;
                $mailN->save();
            }
        }

        $resp->addData( 'res', 'ok' );

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     */
    public static function getDetail( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $profile = TB_Server_Core_Session::get()->getProfile();

        /** @var TB_Shared_Ent_TeamData_Appointment $appointment */
        $appointment = TB_Shared_Ent_TeamData_Appointment::get( $params->get( 'appointment_id' ) );
        if ( !isset( $appointment ) ) {
            throw new Exception( 'Appointment not found: ' . $params->get( 'appointment_id' ) );
        }
        if ( $appointment->team_id != $profile->team_id ) {
            throw new Exception( 'Not allowed to access appointment.' );
        }

        $attendees = TB_Shared_Ent_TeamData_Attendee::getByAppointmentId( $appointment->id );
        $profiles = TB_Shared_Ent_TeamData_Profile::getProfilesByTeamId( $profile->team_id );

        $resp->addData( 'appointment', $appointment );
        $resp->addData( 'attendees', $attendees );
        $resp->addData( 'profiles', $profiles );

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     *
     * @return TB_Server_Core_Response
     */
    public static function getList( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $team = TB_Server_Core_Session::get()->getTeam();
        $appointments = TB_Shared_Ent_TeamData_Appointment::getByTeamId( $team->id );
        $resp->addRowsToData( 'appointments', $appointments );

        /** @var TB_Shared_Ent_TeamData_Appointment $appointment */
        foreach( $appointments as $appointment ) {
            $attendees = TB_Shared_Ent_TeamData_Attendee::getByAppointmentId( $appointment->id );
            $resp->addRowsToData( 'attendees_' . $appointment->id, $attendees );
        }

        $resp->addData( 'team', $team );

        return $resp;
    }

    /**
     * Special Trainer action to set attendee state for foreign profile
     *
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     * @throws Exception
     */
    public static function setAttendanceStatusByTrainer( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        $currentProfile = TB_Server_Core_Session::get()->getProfile();
        if ( !$currentProfile->isTrainer() && !$currentProfile->isCoTrainer() ) {
            throw new Exception( "No rights" );
        }

        /** @var TB_Shared_Ent_TeamData_Appointment $appointment */
        $appointment = TB_Shared_Ent_TeamData_Appointment::get( $params->get( 'appointment_id' ) );
        if ( is_null( $appointment) || $currentProfile->team_id != $appointment->team_id ) {
            throw new Exception( 'Invalid appointment id' );
        }

        /** @var TB_Shared_Ent_TeamData_Profile $profile */
        $profile = TB_Shared_Ent_TeamData_Profile::get( $params->get( 'profile_id' ) );
        if ( is_null( $profile ) || $profile->team_id != $appointment->team_id ) {
            throw new Exception( 'Invalid profile id' );
        }


        // Status
        $status = $params->get( 'status' );
        if ( !in_array( $status, TB_Shared_Ent_TeamData_Attendee::getValidStatus() ) ) {
            throw new Exception( 'Invalid attendee state.' );
        }


        // Update / Create attendee entry
        $attendee = TB_Shared_Ent_TeamData_Attendee::getByAppointmentIdAndProfileId(
            $appointment->id,
            $profile->id
        );

        if ( is_null( $attendee ) ) {
            $attendee = new TB_Shared_Ent_TeamData_Attendee();
            $attendee->appointment_id = $appointment->id;
            $attendee->profile_id = $profile->id;
        }
        $attendee->status = $status;

        // Don't produce News if changed by trainer
        $eh = Francis_Core_EventHandler::get();
        $eh->disable();
        $attendee->save();
        $eh->enable();

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     * @throws Exception
     */
    public static function setAttendanceStatus( TB_Server_Core_RequestData $params ) {
        $resp = new TB_Server_Core_Response();

        /** @var TB_Shared_Ent_TeamData_Appointment $appointment */
        $appointment = TB_Shared_Ent_TeamData_Appointment::get( $params->get( 'appointment_id' ) );

        /** @var TB_Shared_Ent_TeamData_Profile $profile */
        $profile = TB_Server_Core_Session::get()->getProfile();

        if ( $profile->isPlayer() && $appointment->isDealineOver() )
        {
            $resp->addData( 'error', 'timelimit' );
            $resp->addData( 'appointment', $appointment );
        }
        else
        {
            // Required params
            $status = $params->get( 'status' );
            $comment = _xss( $params->get( 'comment' ) );
            $extResult = $params->get( 'ext_result' );

            // Validation
            if ( !in_array( $status, TB_Shared_Ent_TeamData_Attendee::getValidStatus() ) ) {
                throw new Exception( 'Invalid attendee state.' );
            }
            if ( is_null( $appointment ) || $appointment->team_id != $profile->team_id ) {
                throw new Exception( 'Invalid appointment and/or access violation.' );
            }
            if ( $appointment->isOver() ) {
                throw new Exception( 'Appointment is already over.' );
            }

            // Update / Create attendee entry
            $attendee = TB_Shared_Ent_TeamData_Attendee::getByAppointmentIdAndProfileId(
                $appointment->id,
                $profile->id
            );
            if ( is_null( $attendee ) ) {
                $attendee = new TB_Shared_Ent_TeamData_Attendee();
                $attendee->appointment_id = $appointment->id;
                $attendee->profile_id = $profile->id;
            }
            if ( TB_Shared_Ent_TeamData_Attendee::STATUS_ACCEPTED === $status ) {
                $attendee->last_accepted = date("Y-m-d H:i:s");
            }
            $attendee->status = $status;
            if ( !is_null( $comment ) ) {
                $attendee->comment = $comment;
            }
            $attendee->save();

            if ( $extResult ) {
                $numAcc = 0;
                $numDec = 0;
                $atts = TB_Shared_Ent_TeamData_Attendee::getByAppointmentId( $appointment->id );
                /** @var TB_Shared_Ent_TeamData_Attendee $att */
                foreach ( $atts as $att ) {
                    if ( $att->status === TB_Shared_Ent_TeamData_Attendee::STATUS_ACCEPTED ) {
                        $numAcc++;
                    } else if ( $att->status === TB_Shared_Ent_TeamData_Attendee::STATUS_DECLINED ) {
                        $numDec++;
                    }
                }
                $resp->addData( 'ext_result', array(
                    'num_accepted' => $numAcc,
                    'num_declined' => $numDec
                ));
            }
        }

        return $resp;
    }

} 