<?php

  /**
   * Invoice implementation that can be attached to any object
   *
   * @package modules.invoiving
   * @subpackage models
   */
  abstract class IInvoiceBasedOnImplementation {
    
    /**
     * Parent object
     *
     * @var IInvoice
     */
    protected $object;
    
    
    /**
     * Create invoice instance
     * 
     * @param mixed $settings
     * @return Invoice
     */
    abstract function create($settings = null, IUser $user = null); 
    
    /**
     * Construct invoice helper
     *
     * @param IInvoiceBasedOn $object
     */
    function __construct(IInvoiceBasedOn  $object) {
      $this->object = $object;
    } // __construct
    
    /**
     * Add items to the invoice
     * 
     * @param $items
     * @param $invoice
     */
    function addItemsToInvoice($items, Invoice $invoice) {
      //add items
      $position = 1;
      foreach($items as $invoice_item_data) {
        $invoice_item = new InvoiceItem();
        $invoice_item->setAttributes($invoice_item_data);
        $invoice_item->setInvoiceId($invoice->getId());
        $invoice_item->setPosition($position);

        $position++;
        $invoice_item->save();
        
        if($invoice_item_data['time_record_ids']) {
          $tmp = array_var($invoice_item_data, 'time_record_ids');
          if(is_integer($tmp)) {
             $time_record_ids = array();
             $time_record_ids[] = $tmp;
          } else {
            $time_record_ids = $tmp;
          }
          $invoice_item->setTimeRecordIds($time_record_ids);
          $invoice->setTimeRecordsStatus(BILLABLE_STATUS_PENDING_PAYMENT);
        }//if
        
        if($invoice_item_data['expenses_ids']) {
          $tmp_e = array_var($invoice_item_data, 'expenses_ids');
          if(is_integer($tmp_e)) {
             $expenses_ids = array();
             $expenses_ids[] = $tmp_e;
          } else { 
            $expenses_ids = $tmp_e;
          }
          $invoice_item->setExpensesIds($expenses_ids);
          $invoice->setExpensesStatus(BILLABLE_STATUS_PENDING_PAYMENT);
        }//if
      } // foreach
      
    }//addItemsToInvoice
    
    
     /**
      * Create invoice items for object
      *
      * @param $settings
      * @param $user
      * @return $items array
      */
     function createItemsForInvoice($timerecords, $expenses, Project $project = null, $settings = null, IUser $user) {
        $timerecord_ids = array();
        $total_expense = 0;
        $expenses_ids = array();
        
        //time records
        if(is_foreachable($timerecords) || is_foreachable($expenses)) {
          if($settings['settings'] == Invoice::INVOICE_SETTINGS_SUM_ALL) {
            
            if($project instanceof Project) {
              $is_identical = $unit_cost = TimeRecords::isIdenticalJobRate($timerecords,$project);
            }//if
            
            foreach ($timerecords as $timerecord) {
              $job_type = $timerecord->getJobType();
              $timerecord_ids[] = $timerecord->getId();
              if ($timerecord->getValue() > 0 && $job_type instanceof JobType) {
                if(!$is_identical) {
                  //different job hourly rate
                  
                  if(!$project instanceof Project) {
                    //based on time report
                    $project = $timerecord->getProject();
                  }//if
                  
                  $total_time = 1;
                  $unit_cost += $job_type->getHourlyRateFor($project) * $timerecord->getValue();
                } else {
                  //same hourly rate
                  $total_time += $timerecord->getValue();
                }//if
              }//if
            }//foreach
            
            
            if($total_time > 0) {
              if($this->object instanceof TrackingReport) {
                if(!$is_identical) {
                  $description = lang('Total time logged');
                } else {
                  $description = lang('Total of :hours logged', array('hours' => $total_time));
                }//if
              } else {
                $description = $this->object->getVerboseType() . ':' . $this->object->getName();
              }//if
              
              $items[] = array(
                  'description' => $description,
                  'unit_cost' => $unit_cost,
                  'quantity' => $total_time,
                  'subtotal' => $unit_cost * $total_time,
                  'total' => $unit_cost * $total_time,
                  'tax_rate_id' =>  $settings['tax_rate_id'],
                  'time_record_ids' => $timerecord_ids,
              	);
            }//if
            
            
            //loop throught expenses
            foreach ($expenses as $expense) {
              if ($expense->getValue() > 0) {
                $total_expense += $expense->getValue();
                $expenses_ids[] = $expense->getId();
              }//if
            }//foreach
            
        
            if($total_expense > 0) {
              $items[] = array(
                'description' => lang('Other expenses'),
                'unit_cost' => $total_expense,
                'quantity' => 1,
                'subtotal' => $total_expense,
                'total' => $total_expense,
                'tax_rate_id' =>  $settings['tax_rate_id'],
                'expenses_ids' => $expenses_ids,
              );
            }//if
           
            
              
          } elseif ($settings['settings'] == Invoice::INVOICE_SETTINGS_SUM_ALL_BY_JOB_TYPE) {
            
            $grouped = TimeRecords::groupByJobType($timerecords);
            foreach ($grouped as $key => $timerecords) {
              $total_time = 0;
              $timerecord_ids = array();
              foreach($timerecords as $timerecord) {
                if ($timerecord->getValue() > 0) {
                  $total_time += $timerecord->getValue();
                  $timerecord_ids[] = $timerecord->getId();
                  
                  $job_type = $timerecord->getJobType();
                  
                  if(!$project instanceof Project) {
                    //based on time report
                    $project = $timerecord->getProject();
                  }//if
                  
                  $unit_cost = $job_type->getHourlyRateFor($project);
                   
                } //if
              }//foreach

              if($total_time > 0) {
                $items[] = array(
                  'description' => $key,
                  'unit_cost' => $unit_cost,
                  'quantity' => $total_time,
                  'subtotal' => $unit_cost * $total_time,
                  'total' => $unit_cost * $total_time,
                  'tax_rate_id' =>  $settings['tax_rate_id'],
                  'time_record_ids' => $timerecord_ids,
                );
              }//if
            }//foreach
            
            //loop throught expenses
            foreach ($expenses as $expense) {
              if ($expense->getValue() > 0) {
                $total_expense += $expense->getValue();
                $expenses_ids[] = $expense->getId();
              }//if
            }//foreach
            
           if($total_expense > 0) {
             $items[] = array(
                'description' => lang('Other expenses'),
                'unit_cost' => $total_expense,
                'quantity' => 1,
                'subtotal' => $total_expense,
                'total' => $total_expense,
                'tax_rate_id' => $settings['tax_rate_id'],
                'expenses_ids' => $expenses_ids,
              );
           }//if
            
          
          } elseif ($settings['settings'] == Invoice::INVOICE_SETTINGS_KEEP_AS_SEPARATE) { 
            
            
              foreach($timerecords as $timerecord) {
                if ($timerecord->getValue() > 0) {
                  
                  $job_type = $timerecord->getJobType();
                  $description = $timerecord->getJobTypeName();
                  $description .=  $timerecord->getSummary() ? ' - ' .$timerecord->getSummary() : '';
                  
                  if(!$project instanceof Project) {
                    //based on time report
                    $project = $timerecord->getProject();
                  }//if
                  
                  $items[] = array(
                    'description' => $description,
                    'unit_cost' => $job_type->getHourlyRateFor($project),
                    'quantity' => $timerecord->getValue(),
                    'subtotal' => $job_type->getHourlyRateFor($project) * $timerecord->getValue(),
                    'total' => $job_type->getHourlyRateFor($project) * $total_time,
                    'tax_rate_id' => $settings['tax_rate_id'],
                    'time_record_ids' => $timerecord->getId(),
                  );
                }//if
              } // foreach
            
              //loop throught expenses
              foreach ($expenses as $expense) {
                if ($expense->getValue() > 0) {
                  $description_ex = $expense->getCategoryName();
                  $description_ex .=  $expense->getSummary() ? ' - ' .$expense->getSummary() : '';
                  
                  $items[] = array(
                    'description' => $description_ex,
                    'unit_cost' => $expense->getValue(),
                    'quantity' => 1,
                    'subtotal' => $expense->getValue(),
                    'total' => $expense->getValue(),
                    'tax_rate_id' => $settings['tax_rate_id'],
                    'expenses_ids' => $expense->getId(),
                  );
                }//if
              }//foreach
              
          }//if
         
        }//if
        
        return $items;
        
    }//createItemsForInvoice
    
    
    /**
     * Returns true if $user can create invoice
     *
     * @param IUser $user
     * @return boolean
     */
    function canAdd(User $user) {
      return Invoices::canAdd($user);
    } //canMake
    
    /**
     * Return make invoice url
     * 
     * @return string
     */
    function getUrl() {
      return Router::assemble($this->object->getRoutingContext() . '_invoicing', $this->object->getRoutingContextParams());
    }//getUrl
  
  }