<?php
/**
 * @brief		Shipping Order Model
 *
 * @copyright	(c) 2001 - 2016 Invision Power Services, Inc.
 *
 * @package		IPS Community Suite
 * @subpackage	Nexus
 * @since		19 Mar 2014
 * @version		SVN_VERSION_NUMBER
 */

namespace IPS\nexus\Shipping;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
	exit;
}

/**
 * Shipping Order Model
 */
class _Order extends \IPS\Patterns\ActiveRecord
{
	const STATUS_SHIPPED	= 'done';
	const STATUS_PENDING	= 'pend';
	const STATUS_CANCELED	= 'canc';
	
	/**
	 * @brief	Multiton Store
	 */
	protected static $multitons;

	/**
	 * @brief	Database Table
	 */
	public static $databaseTable = 'nexus_ship_orders';
	
	/**
	 * @brief	Database Prefix
	 */
	public static $databasePrefix = 'o_';
	
	/**
	 * Set Default Values
	 *
	 * @return	void
	 */
	public function setDefaultValues()
	{
		$this->status = static::STATUS_PENDING;
		$this->date = new \IPS\DateTime;
	}
	
	/**
	 * Get invoice
	 *
	 * @return	\IPS\nexus\Invoice
	 */
	public function get_invoice()
	{
		return \IPS\nexus\Invoice::load( $this->_data['invoice'] );
	}
	
	/**
	 * Set invoice
	 *
	 * @param	\IPS\nexus\Invoice
	 * @return	void
	 */
	public function set_invoice( \IPS\nexus\Invoice $invoice )
	{
		$this->_data['invoice'] = $invoice->id;
	}
	
	/**
	 * Get data (name, address, phone number)
	 *
	 * @return	mixed
	 */
	public function get_data()
	{
		return json_decode( $this->_data['data'], TRUE );
	}
	
	/**
	 * Set data (name, address, phone number)
	 *
	 * @param	mixed	$data	The data
	 * @return	void
	 */
	public function set_data( $data )
	{
		$this->_data['data'] = json_encode( $data );
	}
	
	/**
	 * Get method
	 *
	 * @return	\IPS\nexus\Shipping\FlatRate
	 */
	public function get_method()
	{
		try
		{
			return \IPS\nexus\Shipping\FlatRate::load( $this->_data['method'] );
		}
		catch ( \Exception $e )
		{
			return NULL;
		}
	}
	
	/**
	 * Set method
	 *
	 * @param	\IPS\nexus\Shipping\FlatRate
	 * @return	void
	 */
	public function set_method( \IPS\nexus\Shipping\FlatRate $method )
	{
		$this->_data['method'] = $method->id;
	}
	
	/**
	 * Get items
	 *
	 * @return	array
	 */
	public function get_items()
	{
		return json_decode( $this->_data['items'], TRUE );
	}
	
	/**
	 * Set items
	 *
	 * @note	Is protected, as addItem should be used
	 * @see		\IPS\nexus\Invoice::addItem()
	 * @param	array	$items	The items
	 * @return	void
	 */
	protected function set_items( array $items )
	{
		$this->_data['items'] = json_encode( $items );
	}
	
	/**
	 * Get date
	 *
	 * @return	\IPS\DateTime
	 */
	public function get_date()
	{
		return \IPS\DateTime::ts( $this->_data['date'] );
	}
	
	/**
	 * Set date
	 *
	 * @param	\IPS\DateTime	$date	The invoice date
	 * @return	void
	 */
	public function set_date( \IPS\DateTime $date )
	{
		$this->_data['date'] = $date->getTimestamp();
	}
	
	/**
	 * Get shipped date
	 *
	 * @return	\IPS\DateTime|NULL
	 */
	public function get_shipped_date()
	{
		return $this->_data['shipped_date'] ? \IPS\DateTime::ts( $this->_data['shipped_date'] ) : NULL;
	}
	
	/**
	 * Set shipped date
	 *
	 * @param	\IPS\DateTime	$date	The invoice date
	 * @return	void
	 */
	public function set_shipped_date( \IPS\DateTime $date )
	{
		$this->_data['shipped_date'] = $date->getTimestamp();
	}
		
	/**
	 * Get label
	 *
	 * @return	\IPS\Http\Url|string|NULL
	 */
	public function get_label()
	{
		try
		{
			return $this->_data['label'] ? \IPS\Http\Url::external( $this->_data['label'] ) : NULL;
		}
		catch ( \InvalidArgumentException $e )
		{
			return $this->_data['label'];
		}
	}
	
	/**
	 * Item Count
	 *
	 * @return	int
	 */
	public function itemCount()
	{
		$count = 0;
		foreach ( $this->items as $item )
		{
			$count += $item['quantity'];
		}
		return $count;
	}
	
	/**
	 * Send Notification
	 *
	 * @return	void
	 */
	public function sendNotification()
	{		
		$email = \IPS\Email::buildFromTemplate( 'nexus', 'shipment', array( $this ), \IPS\Email::TYPE_TRANSACTIONAL );
		$email->send( $this->invoice->member );
	}
	
	/**
	 * @brief	Address
	 */
	protected $_address;
	
	/**
	 * Get address
	 *
	 * @return	\IPS\GeoLocation
	 */
	public function address()
	{
		if ( !$this->_address )
		{
			$data = $this->data;
			
			if ( isset( $data['address'] ) )
			{
				$this->_address = \IPS\GeoLocation::buildFromJson( json_encode( $data['address'] ) );
			}
			else
			{
				$this->_address = new \IPS\GeoLocation;
				$this->_address->addressLines[0] = $data['address_1'];
				if ( isset( $data['address_2'] ) and $data['address_2'] )
				{
					$this->_address->addressLines[1] = $data['address_2'];
				}
				$this->_address->city = $data['city'];
				$this->_address->state = $data['state'];
				$this->_address->zip = $data['zip'];
				$this->_address->country = $data['country'];
			}
		}
		
		return $this->_address;
	}
	
	/**
	 * Tracking URL
	 *
	 * @return	\IPS\Http\Url|NULL
	 */
	public function trackingUrl()
	{
		if ( $this->status === static::STATUS_SHIPPED and $this->service )
		{
			try
			{
				return \IPS\Http\Url::external( $this->service );
			}
			catch ( \InvalidArgumentException $e )
			{
				return NULL;
			}
		}
		return NULL;
	}
	
	/**
	 * ACP "View Invoice" URL
	 *
	 * @return	\IPS\Http\Url
	 */
	public function acpUrl()
	{
		return \IPS\Http\Url::internal( "app=nexus&module=payments&controller=shipping&do=view&id={$this->id}", 'admin' );
	}
	
	/**
	 * ACP Buttons
	 *
	 * @param	string	$ref	Referer
	 * @return	array
	 */
	public function buttons( $ref='v' )
	{
		$url = $this->acpUrl()->setQueryString( 'r', $ref );
		$return = array();
		
		if ( $this->status !== static::STATUS_SHIPPED and \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'payments', 'shiporders_edit' ) )
		{
			$return['ship'] = array(
				'title'		=> 'shipment_ship',
				'icon'		=> 'check',
				'link'		=> $url->setQueryString( 'do', 'ship' ),
				'data'		=> \IPS\Settings::i()->easypost_api_key ? NULL : array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('shipment_ship') )
			);

			if ( $this->status !== static::STATUS_CANCELED )
			{
				$return['cancel'] = array(
					'title'		=> 'cancel',
					'icon'		=> 'times',
					'link'		=> $url->setQueryString( 'do', 'cancel' ),
					'data'		=> array( 'confirm' => '' )
				);
			}
		}
		
		if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'nexus', 'payments', 'shiporders_delete' ) )
		{
			$return['delete'] = array(
				'title'		=> 'delete',
				'icon'		=> 'times-circle',
				'link'		=> $url->setQueryString( 'do', 'delete' ),
				'data'		=> array( 'delete' => '' )
			);
		}
		
		return $return;
	}
	
	/**
	 * Get output for API
	 *
	 * @return	array
	 * @apiresponse		int								id				ID number
	 * @apiresponse		string							status			Status: 'done' = Shipped; 'pend' = Waiting to be shipped; 'canc' = Canceled
	 * @apiresponse		int								invoiceId		Invoice ID Number
	 * @apiresponse		\IPS\nexus\Shipping\FlatRate	method			The shipment method (may be null if using EasyPost)
	 * @apiresponse		object							items			The items in the shipment and their quantities
	 * @apiresponse		datetime						requestDate		When the shipment was requested
	 * @apiresponse		datetime						shipDate		When the shipment was shipped
	 * @apiresponse		\IPS\GeoLocation				address			The delivery address
	 * @apiresponse		string							trackingUrl		The URL to view tracking information, if available
	 */
	public function apiOutput()
	{
		$items = array();
		foreach ( $this->items as $item )
		{
			if ( isset( $items[ $item['name'] ] ) )
			{
				$items[ $item['name'] ] += $item['quantity'];
			}
			else
			{
				$items[ $item['name'] ] = $item['quantity'];
			}
		}
				
		return array(
			'id'			=> $this->id,
			'status'		=> $this->status,
			'invoiceId'		=> $this->invoice->id,
			'method'		=> $this->method ? $this->method->apiOutput() : null,
			'items'			=> $items,
			'requestDate'	=> $this->date->rfc3339(),
			'shipDate'		=> $this->shipped_date ? $this->shipped_date->rfc3339() : null,
			'address'		=> $this->address()->apiOutput(),
			'trackingUrl'	=> $this->trackingUrl() ? ( (string) $this->trackingUrl() ) : null
		);
	}
}