<?php

/**
 * IMPORTANT NOTE
 * The code of this system is closed and a private proprietary of Flex Solutions.
 * A written authorization/license from Flex Solutions is required before using or modifying this code.
 * Email: sales@flexsolution.biz, Phone: +962795342585, Website: http://www.flexsolutions.biz
 */
/*
 * This class will host the web services' methods provided for the POS (client) application
 * For more information about the web services please refer to the following link:
 *  http://www.yiiframework.com/doc/guide/1.1/en/topics.webservice
 */
//error_reporting(~E_DEPRECATED);

class SyncController extends Controller {

    public function actions() {
	return array(
	    // Define that action that will be used to access the methods of this controller
	    'getServices' => array(
		'class' => 'CWebServiceAction',
	    ),
	);
    }

    function mysql_real_escape_string_replacement($inp) {	

	if (!empty($inp) && is_string($inp)) {
	    return str_replace(array('\\', "\x00", "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', "\\0", '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $inp);
	}

	return $inp;
    }

    /**
      The following web service will sync the tickets (from client to server)
      it will first authenticate the user before registering the tickets
      it will take as input the number of tickets to be synced, in addition to the attributes name and attributes values (a long array of values, i.e. concatenated array)
      it will return as output the array of the successfully insterted tickets
      Example of how to call this web service: registerTickets(2, array("id","badge_id"), array("1","12","2","14")), note that the "1" and "2" are tickets' ids whereas the "12" and "14" are the badge_id's
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string the user name (to authenticate him before registering the tickets)
     * @param string the user password
     * @param int the number of tickets that are required to be registered
     * @param string[] the ticket attributes' names that are required to be set
     * @param string[] the ticket attributes' values (concatenated arrays)
     * @return string[] the array of the tickets' IDs that were inserted successfully
     * @soap
     */
    public function registerTickets($username, $password, $tickets_number, $attributes_names, $attributes_values) {
	
	// Create an object of the UserIdentity class in order to authenticate the user before registering the tickets
	$user_identity_object = new UserIdentity($username, $password);
	// Initialize a parameter to indicate to the UserIdentity that the requester for the authentication is the client (in order to not avoid authenticating the POS admins)
	$is_reqested_from_client = true;
	if (!($user_identity_object->authenticate($is_reqested_from_client && $user_identity_object->role != "Finance"))) {
	    return array();
	}

	// Calculate the attributes' count
	$attributes_count = count($attributes_names);

	// Partition the long array into set of arrays (each array represents a full set of the ticket's attributes)
	$tickets_attributes_values_array = array_chunk($attributes_values, $attributes_count);

	// Initialize the single array and the registered_tickets_ids
	$ticket_attributes_values_array = array();
	$registered_tickets_ids = array();

	// Loop through each ticket's array in the partitioned array
	foreach ($tickets_attributes_values_array as $ticket_attributes_values_array) {
	    // Initialize the POST array and POST[Ticket], in order to simulate and use the massive assignment to populate the ticket model <note that we can use any array name, e.g. POST1, array1, etc., the POST name is not a condition>
	    $_POST = array();
	    $_POST["Ticket"] = array();
	    // Populate the $_POST["Ticket"] with the provided attributes
	    for ($i = 0; $i < $attributes_count; $i++) {
		$_POST["Ticket"][$attributes_names[$i]] = $ticket_attributes_values_array[$i];
	    }

	    // Initialize the ticket model and perform the massive assignment
	    $ticket = new Ticket();
	    $ticket->attributes = $_POST['Ticket'];
	    // Check if the model found then update it, else insert it
	    if (Ticket::model()->findByPk($ticket->id)) {
		$ticket->setIsNewRecord(false);
	    } else {
		$ticket->setIsNewRecord(true);
	    }
		Yii::log('Ticket with id '.$ticket->id.' issued_at_server = '.$ticket->issued_at_server);
	    // Save the ticket model
	    if ($ticket->save()) {
		// Add the id of the ticket model to the registered_tickets_ids array
		$registered_tickets_ids[] = $ticket->id;
	    }
	}

	// Return the successfully inserted models
	return $registered_tickets_ids;
    }

    /**
      The following web service will get the badges data (from server to client)
      It will take as input the required attributes to be set and returned
      It will return a long array of the attributes' values of all of the retunred badges, the data of this array may have the following form: array("1","04001638","person_id", "2012-01-01","2012-12-30","5","Active", "2", "04343849",.... etc.)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string[] the required badge attributes' names
     * @return string[] the array of the badges
     * @soap
     */
    public function getBadgesData($attributes_names) {
	// Get all of the badges
	$badge_models_array = Badge::model()->findAll();
	$output_array = array();

	foreach ($badge_models_array as $badge_model) {
	    foreach ($attributes_names as $attribute_name) {
		$output_array[] = $badge_model->$attribute_name ? $this->mysql_real_escape_string_replacement($badge_model->$attribute_name) : $badge_model->$attribute_name;
	    }
	}

	return $output_array;
    }

    /**
      The following web service will get the departments data (from server to client)
      It will take as input the required attributes to be set and returned
      It will return a long array of the attributes' values of all of the retunred departments, the data of this array may have the following form: array("1","Dep1","Loc1","Active", "1","Dep2","Loc1","Active", etc.)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string[] the required department attributes' names
     * @param int the POS Id, to know which POS called the web service, in order to filter the returned data
     * @return string[] the array of the departments
     * @soap
     */
    public function getDepartmentsData($attributes_names, $pos_id) {
	// Get the model of the POS that called this web service
	$pos = Pos::model()->findByPk($pos_id)->with('personPoses');

	// part 1- Get the active departments IDs at the location of the POS
	$departments_ids_in_location_of_pos = array_values(CHtml::listData(Department::model()->findAllByAttributes(array("location_id" => $pos->location_id, "status" => "Active")), 'id', 'id'));

	// part 2- Get the departments of the persons assigned to this pos (the assigned persons to this POS may be from another location, so that their departments will not appear in the previous criteria)
	// Get the assigned persons at the POS
	$person_models_array = Person::model()->findAllByAttributes(array("id" =>
	    array_values(CHtml::listData($pos->personPoses, 'person_id', 'person_id')),
	)); // Note: we use array_values to return a zero based index (i.e. "0"=>"val1", "1"=>"val2",  not "val1"=>"val1")
	// Get the departments IDs of the persons assigned to the POS
	$departments_ids_for_persons_at_pos = array_values(CHtml::listData($person_models_array, 'department_id', 'department_id'));


	// Merge the departments' IDs from both sources
	$merged_department_ids = array_merge($departments_ids_in_location_of_pos, $departments_ids_for_persons_at_pos);

	// Find the departments by their IDs, the following criteria may generate "select * from department where id in (1,2,1,6,4,2)"
	$department_models_array = Department::model()->findAllByAttributes(array("id" => $merged_department_ids));

	$output_array = array();

	foreach ($department_models_array as $department_model) {
	    foreach ($attributes_names as $attribute_name) {
		$output_array[] = $department_model->$attribute_name ? $this->mysql_real_escape_string_replacement($department_model->$attribute_name) : $department_model->$attribute_name;
	    }
	}

	return $output_array;
    }

    /**
      The following web service will get the IssuingReasons data (from server to client)
      It will take as input the required attributes to be set and returned
      It will return a long array of the attributes' values of all of the retunred IssuingReasons, the data of this array may have the following form: array("1","Reason 1", "Active", "2", "Reason 2", "Active", etc.)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string[] the required issuing reason attributes' names
     * @return string[] the array of the issuing reasons
     * @soap
     */
    public function getIssuingReasonsData($attributes_names) {
	// Get the Active issuing reasons
	$issuing_reason_models_array = IssuingReason::model()->findAllByAttributes(array("status" => "Active"));
	$output_array = array();

	foreach ($issuing_reason_models_array as $issuing_reason_model) {
	    foreach ($attributes_names as $attribute_name) {
		$output_array[] = $issuing_reason_model->$attribute_name ? $this->mysql_real_escape_string_replacement($issuing_reason_model->$attribute_name) : $issuing_reason_model->$attribute_name;
	    }
	}

	return $output_array;
    }

    /**
      The following web service will get the Persons data (from server to client)
      It will take as input the required attributes to be set and returned
      It will return a long array of the attributes' values of all of the retunred Persons, the data of this array may have the following form: array("1","21521254","Person Name", "Dep Id", "Active", "2", "84744463", "Person Name 2",... etc.)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string[] the required person attributes' names
     * @param int the POS Id, to know which POS called the web service, in order to filter the returned data
     * @return string[] the array of the badges
     * @soap
     */
    public function getPersonsData($attributes_names, $pos_id) {
	// Get the model of the POS that called this web service, and fetch the persons assigned to it
	$pos = Pos::model()->findByPk($pos_id)->with('personPoses');

	// Get the assigned persons at the POS (note that no need to return only the active persons since their badges will be inactive)
	$person_models_array = Person::model()->findAllByAttributes(array("id" =>
	    array_values(CHtml::listData($pos->personPoses, 'person_id', 'person_id'))
	)); // Note: we use array_values to return a zero based index (i.e. "0"=>"val1", "1"=>"val2",  not "val1"=>"val1")

	$output_array = array();

	foreach ($person_models_array as $person_model) {
	    foreach ($attributes_names as $attribute_name) {
		$output_array[] = $person_model->$attribute_name ? $this->mysql_real_escape_string_replacement($person_model->$attribute_name) : $person_model->$attribute_name;
	    }
	}

	return $output_array;
    }

    /**
      The following web service will get the Schedules data (from server to client)
      It will take as input the required attributes to be set and returned
      It will return a long array of the attributes' values of all of the retunred Schedules, the data of this array may have the following form: array("1","breakfast","start_time", "end_time", "sat", .., "fri", "Active", "2", "Lunch", ....,  etc.)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string[] the required schedule attributes' names
     * @param int the POS Id, to know which POS called the web service, in order to filter the returned data
     * @return string[] the array of the schedules
     * @soap
     */
    public function getSchedulesData($attributes_names, $pos_id) {
	// Get the model of the POS that called this web service, and fetch the schedules assigned to it
	$pos = Pos::model()->findByPk($pos_id)->with('posSchedules');

	// Get the active and assigned schedules at the POS
	$schedule_models_array = Schedule::model()->findAllByAttributes(array("status" => "Active",
	    "id" =>
	    array_values(CHtml::listData($pos->posSchedules, 'schedule_id', 'schedule_id'))
	)); // Note: we use array_values to return a zero based index (i.e. "0"=>"val1", "1"=>"val2",  not "val1"=>"val1")
	$output_array = array();

	foreach ($schedule_models_array as $schedule_model) {
	    foreach ($attributes_names as $attribute_name) {
		$output_array[] = $schedule_model->$attribute_name ? $this->mysql_real_escape_string_replacement($schedule_model->$attribute_name) : $schedule_model->$attribute_name;
	    }
	}

	return $output_array;
    }

    /**
      The following web service will get the Users data (from server to client)
      It will take as input the required attributes to be set and returned
      It will return a long array of the attributes' values of all of the retunred Users, the data of this array may have the following form: array("1","usr1", "email1","pwd1", "POS Admin", "Active", "2","usr2","email2","pwd2", "Active", ....,  etc.)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string[] the required user attributes' names
     * @param int the POS Id, to know which POS called the web service, in order to filter the returned data
     * @return string[] the array of the users
     * @soap
     */
    public function getUsersData($attributes_names, $pos_id) {
	// Get the model of the POS that called this web service
	$pos = Pos::model()->findByPk($pos_id)->with('location');

	// Get all the active users at the location of the POS
	$user_models_array = VUser::model()->findAllByAttributes(array("location" => $pos->location->code, "status" => "Active"));
	$output_array = array();

	foreach ($user_models_array as $user_model) {
	    foreach ($attributes_names as $attribute_name) {
		$output_array[] = $user_model->$attribute_name ? $this->mysql_real_escape_string_replacement($user_model->$attribute_name) : $user_model->$attribute_name;
	    }
	}

	return $output_array;
    }

    /**
      The following web service will get the tickets that were issued at server for a specific POS (i.e. the tickets that were issued using the use case "Issue Department Ticket" using the web interface)
      It will take as input the pos_id, and the ticket ID of the last synced server ticket for that POS
      It will return a long array of the values of the tickets, i.e.. (ticket_id, department_name, schedule_name, date_time, quantity, issuing_reason_name, username, ...., ticket_id2, department_name2, ..., etc...)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string the pos_id
     * @param string the last_synced_server_ticket_id
     * @return string[] the array of the server tickets
     * @soap
     */
    public function getServerTickets($pos_id, $last_synced_server_ticket_id) {
	
	if (!$last_synced_server_ticket_id)
	    $last_synced_server_ticket_id = 0;
	Yii::log('Server Tickets Sync, last synced server id= '.$last_synced_server_ticket_id);
	$tickets_models = Ticket::model()->with(array('department', 'schedule', 'issuingReason', 'user'))->findAll(array(
	    'condition' => 'pos_id=:pos_id 
                                                                        AND
                                                                      t.id > :last_synced_server_ticket_id
                                                                        AND
                                                                      issued_at_server = 1
                                                                        AND
                                                                      cancelled = 0
                                                                      ',
	    'params' => array(':pos_id' => $pos_id,
		':last_synced_server_ticket_id' => $last_synced_server_ticket_id),
	    'order' => 't.id ASC'
	));
	$output_array = array();

	foreach ($tickets_models as $ticket_model) {
	    $output_array[] = $ticket_model->id;
	    $output_array[] = $ticket_model->department->name;
	    $output_array[] = $ticket_model->schedule->name;
	    $output_array[] = date("Y-m-d", strtotime($ticket_model->date_time));
	    $output_array[] = $ticket_model->quantity;
	    $output_array[] = $ticket_model->issuingReason->reason;
	    $output_array[] = $ticket_model->user->getIdentifier();
	}

	return $output_array;
    }

    /**
      The following web service will try to authenticate a user
      It will take as input the username and password
      It will return an array
      ("UserId, "-1" if the authentication failed", "the user role if he was authenticated successfully")
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string the user name
     * @param string the user password
     * @return string[] the output array ("UserId, "-1" if the authentication failed", "the user role if he was authenticated successfully")
     * @soap
     */
    public function authenticatetUser($username, $password) {
	$output_array = array();
	// Create an object of the UserIdentity class and pass the username and password to it
	$user_identity_object = new UserIdentity($username, $password);
	// Initialize a parameter to indicate to the UserIdentity that the requester for the authentication is the client (in order to not avoid authenticating the POS admins)
	$is_reqested_from_client = true;
	if ($user_identity_object->authenticate($is_reqested_from_client && $user_identity_object->role != "Finance")) {
	    $output_array[] = $user_identity_object->id;
	    $output_array[] = $user_identity_object->role;
	} else {
	    $output_array[] = "-1";
	    $output_array[] = "";
	}
	return $output_array;
    }

    /**
      The following web service will get the active locations in the system
      It will return an array of the ' codes
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @return string[] the array of the locations
     * @soap
     */
    public function getLocations() {
	// Get the model of the POS that called this web service
	$locations = Location::model()->findAllByAttributes(array("status" => "Active"));

	$output_array = array_values(CHtml::listData($locations, 'code', 'code'));

	return $output_array;
    }

    /**
      The following web service will register the POS information on the server
      It will return the registered POS Id (-1 in case an error occured)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string the POS name
     * @param string the POS location code
     * @param string the POS description
     * @param string the POS user id
     * @param string the POS mac address
     * @return string either "-1" if the registration failed, or the registered POS id
     * @soap
     */
    public function registerPOS($pos_name, $pos_location_code, $pos_description, $user_id, $mac_address) {
	$pos_model = Pos::model()->findByAttributes(array("name" => $pos_name));
	$location = Location::model()->findByAttributes(array("code" => $pos_location_code));

	if ($pos_model != null) {
	    $pos_model->installation_date = date('Y-m-d');
	} else {
	    $pos_model = new Pos();
	    $pos_model->name = $pos_name;
	    $pos_model->location_id = $location->id;
	    $pos_model->description = $pos_description;
	    $pos_model->user_id = $user_id;
	    $pos_model->mac_address = $mac_address;
	    $pos_model->installation_date = date('Y-m-d');
	    $pos_model->status = "Active";
	}

	if ($pos_model->save()) {
	    return $pos_model->id;
	} else {
	    return "-1";
	}
    }

    /**
      The following web service will get the POS status, i.e. either Active or Inactive
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string the POS Id
     * @return string the POS status
     * @soap
     */
    public function getPosStatus($pos_id) {
	// Get the POS model
	$pos = Pos::model()->findByPk($pos_id);

	return $pos->status;
    }

    /**
      The following web service will change the user password of the POS admin)
      <please don't edit the following comments becasue they will be used as a doc-comment of the web service>
     * @param string the user id
     * @param string the current_password
     * @param string the new_password
     * @return string ("-2" the user not found or an error occured, "-1" the old and new password didn't match, "the value of the new password" if it was changed successfully)
     * @soap
     */
    public static function changePassword($user_id, $current_password, $new_password) {
	$user = User::model()->findByPk($user_id);
	if ($user) {
	    if ($user->password != User::encrypt($user->email . $current_password)) {
		return "-1";
	    } else {
		$user->password = User::encrypt($user->email . $new_password);
		if ($user->save(false)) { // we pass false to avoid the validation, because the validation will encrypt the password, but we've already encrypt it
		    return $user->password;
		} else {
		    return "-2";
		}
	    }
	} else {
	    return "-2";
	}
    }

}
