<?php 
  /**
   * Class that generates the pdf
   * 
   * @author Goran Radulovic
   * @package activeCollab.modules.invoicing
   * @subpackage models
   */

  // class is based on TCPDF so we need to include it
  require_once(ANGIE_PATH .'/classes/tcpdf/init.php');

  class InvoiceTCPDF extends TCPDF {
    
    /**
     * Invoice instance
     * 
     * @var IInvoice
     */
    private $invoice;
    
    /**
     * Invoice template
     * 
     * @var InvoiceTemplate
     */
    private $template;
    
    /**
     * Generated header height
     * 
     * @var float
     */
    private $generated_header_height;

    /**
     * Line Height
     *
     * @var int
     */
    private $line_height = 3;
    
    /**
     * Is common tax rate for all items in invocie
     * 
     * @var $is_common_tax boolean
     */
    private $is_common_tax = false;
    
    /**
     * Class constructor
     * 
     * @param IInvoice $invoice
     */
    function __construct(IInvoice $invoice) {
      $this->invoice = $invoice;
      $this->template = new InvoiceTemplate();
      
      $this->is_common_tax = boolval($this->invoice->commonTaxRate());
      
      parent::__construct();
      
      $this->paper_format = $this->template->getPaperSize();
      $this->paper_orientation = Globalization::PAPER_ORIENTATION_PORTRAIT;
      
      // margins
      $this->SetLeftMargin(15);
      $this->SetRightMargin(15);

      $this->setHeaderMargin(10);
      $this->setFooterMargin(10);
            
      $this->SetTitle($this->invoice->getName(), true);
      $this->SetAuthor('activeCollab (http://www.activecollab.com/)');
      $this->SetCreator('activeCollab (http://www.activecollab.com/)');
      $this->SetAutoPageBreak(true, 20);
      $this->AddPage($this->paper_orientation, $this->paper_format); 
    } // __construct
    
    /**
     * Calculate column width
     * 
     * @param number $column_id
     * @return float
     */
    function getColumnWidth($column_id) {
        if($this->invoice->getTax() != 0) {
          //print tax cell
          if($this->is_common_tax) {
            //common tax - one cell
          $column_widths = array(0 => '5', 1 => '42', 2 => '12', 3 => '12', 4 => '17', 5 => '12');
          } else {
            //different taxes - two cell
            $column_widths = array(0 => '5', 1 => '33', 2 => '12', 3 => '12', 4 => '14', 5 => '12', 6 => '10');
          }//if
        } else {
          //without tax
          $column_widths = array(0 => '5', 1 => '59', 2 => '12', 3 => '12', 4 => '0', 5 => '12');
        }
      
      return (($this->getPageWidth() - $this->lMargin - $this->rMargin ) * $column_widths[$column_id] / 100);
    } // getColumnWidth
    
        
    /**
     * Generate the invoice
     * 
     * @param void
     * @return null
     */
    function generate() {  
      // initial page offset
      if ($this->template->getPrintLogo() || $this->template->getPrintCompanyDetails()) {
        $this->SetTopMargin($this->generated_header_height + $this->getHeaderMargin());
        $this->SetY($this->GetY() + 5);
      } else {
        $this->SetTopMargin(47.78);
        $this->SetY($this->tMargin + 5);
      } // if
      
      $max_details_block_width = 60/100 * ($this->getPageWidth() - $this->lMargin - $this->rMargin);
      $max_client_block_width = 40/100 * ($this->getPageWidth() - $this->lMargin - $this->rMargin);
      $invoice_top_start = $this->GetY();

      // INVOICE DETAILS
      $text_rgb = $this->convertHTMLColorToDec($this->template->getInvoiceDetailsTextColor());
      $this->SetTextColor($text_rgb['R'], $text_rgb['G'], $text_rgb['B']);
      
      if ($this->template->getBodyLayout() == 1) {
        $invoice_details_starting_x = $this->lMargin;
        $text_alignment = 'L';        
      } else {
        $invoice_details_starting_x = $this->getPageWidth() - $max_details_block_width - $this->lMargin;
        $text_alignment = 'R';
      } // if
      
      $this->SetFont($this->template->getInvoiceDetailsFont(), 'B', $this->template->getFontSize() + 6);
      $this->SetX($invoice_details_starting_x);
      $this->MultiCell($max_details_block_width, $this->line_height, $this->invoice->getName(), null, $text_alignment, false, false);
      $this->Ln();
      $this->SetY($this->GetY() + 2);
      
      $this->SetFont($this->template->getInvoiceDetailsFont(), '', $this->template->getFontSize());
      $invoice_details_content = '';

      // Details for invoice
      if($this->invoice instanceof Invoice) {
        if($this->invoice->getProject() instanceof Project) {
          $invoice_details_content .= lang('Project: :project_name', array('project_name' => $this->invoice->getProject()->getName()), true, $this->invoice->getLanguage()) . "\n";
        } // if

        if($this->invoice->getStatus() >= INVOICE_STATUS_ISSUED) {
          if($this->invoice->getIssuedOn()) {
            $invoice_details_content .= lang('Issued On: :issued_date', array('issued_date' => $this->invoice->getIssuedOn()->formatDateForUser(Authentication::getLoggedUser(), 0)), true, $this->invoice->getLanguage()) . "\n";
          } // if

          if($this->invoice->getDueOn()) {
            $invoice_details_content .= lang('Payment Due On: :due_date', array('due_date' => $this->invoice->getDueOn()->formatForUser(Authentication::getLoggedUser(), 0)), true, $this->invoice->getLanguage()) . "\n";
          } // if
        } // if
      } // if

      // Details for quotes
      if($this->invoice instanceof Quote) {
        if($this->invoice->getStatus() >= QUOTE_STATUS_SENT && $this->invoice->getSentOn()) {
          $invoice_details_content .= lang('Sent On: :sent_date', array('sent_date' => $this->invoice->getSentOn()->formatDateForUser(Authentication::getLoggedUser(), 0)), true, $this->invoice->getLanguage()) . "\n";
        } // if
      } // if
 
      $this->SetX($invoice_details_starting_x);
      $this->MultiCell($max_details_block_width, $this->template->getLineHeight(), $invoice_details_content, 0, $text_alignment, false, 1, '', '', true, 0, false, 1.5);
      $this->Ln();
      $invoice_details_end = $this->GetY();
      
      // CLIENT COMPANY
      $corner_width = 3;      
      $padding = 0;
      
      $max_block_width = 40/100 * ($this->getPageWidth() - $this->lMargin - $this->rMargin);
      
      if ($this->template->getBodyLayout() == 1) {
        $client_info_starting_x = $this->getPageWidth() - $max_block_width - $this->lMargin;
        $text_alignment = 'R';
      } else {
        $client_info_starting_x = $this->lMargin; 
        $text_alignment = 'L';  
      } // if
      
      $this->SetY($invoice_top_start);     
      
      $text_rgb = $this->convertHTMLColorToDec($this->template->getClientDetailsTextColor());
      $this->SetTextColor($text_rgb['R'], $text_rgb['G'], $text_rgb['B']);
      
      $this->SetY($invoice_top_start + $padding + 0);
      $this->SetX($client_info_starting_x + $padding);
      $this->SetFont($this->template->getClientDetailsFont(), 'B', $this->template->getFontSize());
      $this->Cell($max_client_block_width - (2 * $padding), $this->line_height + 3, $this->invoice->getCompanyName(), 0, 0, $text_alignment);
      $this->Ln();

      $this->SetX($client_info_starting_x + $padding);
      $this->SetFont($this->template->getClientDetailsFont(), '', $this->template->getFontSize());
      $this->MultiCell($max_client_block_width - (2 * $padding), $this->getFontSize(), $this->invoice->getCompanyAddress(), 0, $text_alignment, false, 1, '', '', true, 0, false, 1.25);
      $client_details_text_bottom = $this->GetY();
      
      $this->Ln();
      
      $client_details_bottom = $this->GetY();
      $this->SetY(max(array($client_details_bottom, $invoice_details_end)));
      
      // ITEMS TABLE HEADER   
      $this->SetY($this->GetY() + 5);
      
      $rgb = $this->convertHTMLColorToDec($this->template->getItemsTextColor());
      $this->SetTextColor($rgb['R'],$rgb['G'],$rgb['B']);                 
      $this->SetFont($this->template->getItemsFont(),'B',$this->template->getFontSize());
      
      $cell_border = 0;
      if ($this->template->getPrintItemsBorder()) {
        $rgb = $this->convertHTMLColorToDec($this->template->getItemsBorderColor());
        $this->SetDrawColor($rgb['R'], $rgb['G'], $rgb['B']);
        $cell_border = 'B';
      } // if     
      
      if ($this->template->getPrintTableBorder()) {
        $rgb = $this->convertHTMLColorToDec($this->template->getTableBorderColor());
        $this->SetDrawColor($rgb['R'], $rgb['G'], $rgb['B']);
        $cell_border = 'B';
      } // if
      
      $this->Cell($this->getColumnWidth(0), $this->template->getFontSize(), '#', $cell_border, 0, 'R', false, false);
      $this->Cell($this->getColumnWidth(1), $this->template->getFontSize(), lang('Description', null, true, $this->invoice->getLanguage()), $cell_border, 0, 'L', false, false);
      $this->Cell($this->getColumnWidth(2), $this->template->getFontSize(), lang('Qty.', null, true, $this->invoice->getLanguage()), $cell_border, 0, 'R', false, false);
      $this->Cell($this->getColumnWidth(3), $this->template->getFontSize(), lang('Unit Cost', null, true, $this->invoice->getLanguage()), $cell_border, 0, 'R', false, false);
      //head
      
      if($this->invoice->getTax() != 0) {
        if($this->is_common_tax) {
          
          $this->Cell($this->getColumnWidth(4), $this->template->getFontSize(), $this->invoice->getTaxColumnText(), $cell_border, 0, 'R', false, false);
        } else {
          $this->Cell($this->getColumnWidth(4)+$this->getColumnWidth(6), $this->template->getFontSize(), $this->invoice->getTaxColumnText(), $cell_border, 0, 'R', false, false);
        }//if
      }//if
      
      $this->Cell($this->getColumnWidth(5), $this->template->getFontSize(), lang('Total', null, true, $this->invoice->getLanguage()), $cell_border, 0, 'R', false, false);
       $this->Ln();
       
       // INVOICE ITEMS
      
      //  remember starting coordinates      
      $starting_x = $this->GetX();
      
      $this->setCellPaddings(0, 1, 0, 1);
      $this->SetFont($this->template->getItemsFont(), '', $this->template->getFontSize());
      $items = $this->invoice->getItems();
      if (is_foreachable($items)) {
        $row_id = 1;
        foreach ($items as $item) {          
           // determine row height
          $this->startTransaction();          
          $details_col_start_y = $this->GetY();
          $this->SetX($starting_x + $this->getColumnWidth(0));
           $this->MultiCell($this->getColumnWidth(1), 1, $item->getDescription(), $cell_border, 'L', false, false);
           $this->Ln();
           $details_col_end_y = $this->GetY();
           $row_height = $details_col_end_y - $details_col_start_y;           
          $this->rollbackTransaction(true);
                    
           // add new page if we need it
          if ($details_col_end_y > ($this->getPageHeight() - $this->bMargin)) {
            $this->AddPage();
          } // if
                    
          $cell_border = 0;
          // if print items border is enabled set the border style
          if ($this->template->getPrintItemsBorder()) {
            $rgb = $this->convertHTMLColorToDec($this->template->getItemsBorderColor());
            $this->SetDrawColor($rgb['R'], $rgb['G'], $rgb['B']);
            $cell_border = 'B';
          } // if

          // if print table border is enabled set the border style
          if ($this->template->getPrintTableBorder() && $row_id == count($items)) {
            $rgb = $this->convertHTMLColorToDec($this->template->getTableBorderColor());
            $this->SetDrawColor($rgb['R'], $rgb['G'], $rgb['B']);
            $cell_border = 'B';
          } // if
            
          $this->SetX($starting_x);
          $this->MultiCell($this->getColumnWidth(0), $row_height, $row_id.'. ', $cell_border, 'R', false, false);
          $this->MultiCell($this->getColumnWidth(1), $row_height, ' ' .   $item->getDescription(), $cell_border, 'L', false, false);
          $this->MultiCell($this->getColumnWidth(2), $row_height, $item->getQuantity(), $cell_border, 'R', false, false);
          $this->MultiCell($this->getColumnWidth(3), $row_height, number_format($item->getUnitCost(), 2, NUMBER_FORMAT_DEC_SEPARATOR, NUMBER_FORMAT_THOUSANDS_SEPARATOR), $cell_border, 'R', false, false);
          
          //item tax
          if($this->invoice->getTax() != 0) {
            if($this->is_common_tax) {
              //same tax rate
              $this->MultiCell($this->getColumnWidth(4), $row_height, number_format($item->getTax(), 2, NUMBER_FORMAT_DEC_SEPARATOR, NUMBER_FORMAT_THOUSANDS_SEPARATOR), $cell_border, 'R', false, false);
            } else {
              //diferent tax rate
              $tax_name = $item->getTaxRateName() . " " . $item->getTaxRatePercentageVerbose();
              $this->MultiCell($this->getColumnWidth(4), $row_height, $tax_name, $cell_border, 'R', false, false);
              $this->MultiCell($this->getColumnWidth(6), $row_height, number_format($item->getTax(), 2, NUMBER_FORMAT_DEC_SEPARATOR, NUMBER_FORMAT_THOUSANDS_SEPARATOR), $cell_border, 'R', false, false);
            }//if
          }//if
          
          $this->MultiCell($this->getColumnWidth(5), $row_height, number_format($item->getTotal(), 2, NUMBER_FORMAT_DEC_SEPARATOR, NUMBER_FORMAT_THOUSANDS_SEPARATOR), $cell_border, 'R', false, false);
          $this->Ln();
          $row_id ++;
         } // foreach   
      } // if
      
      // INVOICE TOTALS
      if($this->invoice->getTax() != 0) {
        if($this->is_common_tax) {
          $col1_width = $this->getColumnWidth(3);
          $col2_width = $this->getColumnWidth(4) + $this->getColumnWidth(5);
          $starting_x = $this->lMargin + $this->getColumnWidth(0) + $this->getColumnWidth(1) + $this->getColumnWidth(2);      
        } else {
          $col1_width = $this->getColumnWidth(4);
          $col2_width = $this->getColumnWidth(6) + $this->getColumnWidth(5);
          $starting_x = $this->lMargin + $this->getColumnWidth(0) + $this->getColumnWidth(1) + $this->getColumnWidth(2) + $this->getColumnWidth(3);   
        }
      } else {
        $col1_width = $this->getColumnWidth(3);
        $col2_width = $this->getColumnWidth(4) + $this->getColumnWidth(5) + $this->getColumnWidth(2);
        $starting_x = $this->lMargin + $this->getColumnWidth(0) + $this->getColumnWidth(1);      
      }//if
      
      $cell_border = 0;
      if ($this->template->getPrintItemsBorder()) {
        $rgb = $this->convertHTMLColorToDec($this->template->getItemsBorderColor());
        $this->SetDrawColor($rgb['R'], $rgb['G'], $rgb['B']);
        $cell_border = 'B';
      } // if
      
      $this->SetX($starting_x);
      $this->Cell($col1_width, $this->template->getLineHeight(), lang('Subtotal:', null, true, $this->invoice->getLanguage()), $cell_border, 0, 'R', false, false);
      $this->Cell($col2_width, $this->template->getLineHeight(), number_format($this->invoice->getTotal(), 2, NUMBER_FORMAT_DEC_SEPARATOR, NUMBER_FORMAT_THOUSANDS_SEPARATOR), $cell_border, 0, 'R', false, false);
      $this->Ln();
      $this->SetX($starting_x);
      $this->Cell($col1_width, $this->template->getLineHeight(), lang('Tax:', null, true, $this->invoice->getLanguage()), $cell_border, 0, 'R', false, false);
      $this->Cell($col2_width, $this->template->getLineHeight(), number_format($this->invoice->getTax(), 2, NUMBER_FORMAT_DEC_SEPARATOR, NUMBER_FORMAT_THOUSANDS_SEPARATOR), $cell_border, 0, 'R', false, true);
      $this->Ln();
      
      if ($this->template->getPrintTableBorder()) {
        $rgb = $this->convertHTMLColorToDec($this->template->getTableBorderColor());
        $this->SetDrawColor($rgb['R'], $rgb['G'], $rgb['B']);
        $cell_border = 'B';
      } // if
      
      $this->SetFont($this->template->getItemsFont(), 'B', $this->template->getFontSize());
      $this->SetX($starting_x);
      $this->Cell($col1_width, $this->template->getLineHeight(), lang('Total:', null, true, $this->invoice->getLanguage()), $cell_border, 0, 'R', false, false);
      $this->Cell($col2_width, $this->template->getLineHeight(), $this->invoice->getCurrencyCode() . ' ' . number_format($this->invoice->getTaxedTotal(), 2, NUMBER_FORMAT_DEC_SEPARATOR, NUMBER_FORMAT_THOUSANDS_SEPARATOR), $cell_border, 0, 'R', false, true);
      $this->Ln();
      
      // INVOICE NOTE
      if (!trim($this->invoice->getNote())) {
        return true;
      } // if
      $this->SetY($this->GetY() + 10);
      $rgb = $this->convertHTMLColorToDec($this->template->getNoteTextColor());
      $this->SetTextColor($rgb['R'],$rgb['G'],$rgb['B']);
      $this->SetFont($this->template->getNoteFont(), 'B', $this->template->getFontSize());
      $this->Cell(0, $this->template->getLineHeight(), lang('Note', null, null, $this->invoice->getLanguage()) . ':');
      $this->Ln();
      $this->SetFont($this->template->getNoteFont(), '', $this->template->getFontSize());
      $this->MultiCell(0, $this->template->getLineHeight(), $this->invoice->getNote(), 0, 'L', false, 1, '', '', true, 0, false, 0);
    } // generate
    
    /**
     * Function which renders the header (and page background if needed)
     * 
     * @param void
     * @return null
     */
    function Header() {
      // page background if its enabled
      if ($this->template->hasBackgroundImage()) {
        // @TUTORIAL http://www.tcpdf.org/examples/example_051.phps
        $bMargin = $this->getBreakMargin();
        $auto_page_break = $this->AutoPageBreak;
        $this->SetAutoPageBreak(false, 0);
        $this->Image($this->template->getBackgroundImagePath(), 0, 0, $this->getPageWidth(), $this->getPageHeight(), '', '', '', false, 300, 'C', false, false, 0);
        $this->SetAutoPageBreak($auto_page_break, $bMargin);
        $this->setPageMark();
      } // if
      
      if (!$this->template->getPrintLogo() && !$this->template->getPrintCompanyDetails()) {
        return false;
      } // if
      
      $max_block_width = 40/100 * ($this->getPageWidth() - $this->lMargin - $this->rMargin);
      $start_y = $this->GetY();
      
      // font style
      $text_rgb = $this->convertHTMLColorToDec($this->template->getHeaderTextColor());
      $this->SetTextColor($text_rgb['R'], $text_rgb['G'], $text_rgb['B']);
      $this->SetFont($this->template->getHeaderFont(),'',$this->template->getFontSize());

      $details_height = 0;
      $details_start = $this->GetY();
      
      // print details if you enabled the company details
      if ($this->template->getPrintCompanyDetails()) {
        if ($this->template->getHeaderLayout()) {
          $text_alignment = 'L';
          $this->SetX($this->lMargin);
        } else {
          $text_alignment = 'R';
          $this->SetX($this->getPageWidth() - $this->rMargin - $max_block_width);
        } // if
        $this->MultiCell($max_block_width, $this->template->getFontSize(), trim($this->template->getCompanyName() . "\n" . $this->template->getCompanyDetails()), 0, $text_alignment, false, 1, '', '', true, 0, false, 1.25);
        $details_end = $this->GetY();
        $details_height = $details_end - $details_start;
      } // if

      $calculated_height = 0;
      if ($this->template->hasLogoImage() && $this->template->getPrintLogo()) {
        // get constraints
        $max_logo_width = 50/100 * ($this->getPageWidth() - $this->lMargin - $this->rMargin);
        $max_logo_height = $details_height > 20 ? ($details_height > 30 ? 30 : $details_height) : 20;

        // get the real logo dimensions
        $logo_info = getimagesize($this->template->getLogoImagePath());
        $logo_info_width = $logo_info[0];
        $logo_info_height = $logo_info[1];

        $ratio = min($max_logo_width / $logo_info_width, $max_logo_height / $logo_info_height); // calculate the resize ratio

        $calculated_width = floor($logo_info_width * $ratio); // calculate new width
        $calculated_height = floor($logo_info_height * $ratio); // calculate new height

        $logo_y_offset = ($details_height - $calculated_height) / 2; // get the vertical logo offset
        $logo_y_offset = $logo_y_offset < 0 ? 0 : $logo_y_offset  ; // make sure that we get valid vertical offset

        $align = $this->template->getHeaderLayout() ? 'R' : 'L'; // find out how to align logo
        
        $this->Image($this->template->getLogoImagePath(), 0, $start_y + $logo_y_offset, $calculated_width, $calculated_height, false, false, false, false, false, $align);
      } // if

      $current_y = max($calculated_height, $details_height) + $details_start; // calculate the height of current header
      
      // header border
      if ($this->template->getPrintHeaderBorder()) {
        $this->SetLineStyle(array('color' => $this->convertHTMLColorToDec($this->template->getHeaderBorderColor())));
        $this->Line($this->lMargin, $current_y + 5, $this->getPageWidth() - $this->lMargin, $current_y + 5);
      } // if
      
      $this->generated_header_height = $current_y + 5; // remember the header height
    } // Header
    
    /**
     * Function which renders the footer
     * 
     * @param void
     * @return null
     */
    function Footer() {
      // footer font style
      if ($this->template->getPrintFooter()) {
        $rgb = $this->convertHTMLColorToDec($this->template->getFooterTextColor());
        $this->SetTextColor($rgb['R'],$rgb['G'],$rgb['B']);
        $this->SetFont($this->template->getFooterFont(),'',$this->template->getFontSize());

        if ($this->template->getPrintFooterBorder()) {
          $this->SetY(-10 - $this->template->getFontSize());
          $this->SetLineStyle(array('color' => $this->convertHTMLColorToDec($this->template->getFooterBorderColor())));
          $this->Line($this->lMargin, $this->GetY()+2, $this->getPageWidth() - $this->lMargin, $this->GetY()+2);
        } else {
          $this->SetY(-10 - $this->template->getFontSize());
        } // if

        $this->SetY($this->GetY() + 5);

        if ($this->template->getFooterLayout()) {
          $this->SetX($this->getPageWidth() - $this->rMargin - 60);
          $this->Cell(60, $this->template->getLineHeight(),$this->invoice->getName(), 0, 0, 'R');
          $this->SetX($this->lMargin);
          $this->Cell(0, $this->template->getLineHeight(), lang('Page :page_no of :total_pages', array('page_no' => $this->PageNo(), 'total_pages' => $this->getAliasNbPages()), true, $this->invoice->getLanguage()), 0, 0, 'L');
        } else {
          $this->SetX($this->getPageWidth() - $this->rMargin - 34);
          $this->Cell(40, $this->template->getLineHeight(),lang('Page :page_no of :total_pages', array('page_no' => $this->PageNo(), 'total_pages' => $this->getAliasNbPages()), true, $this->invoice->getLanguage()), 0, 0, 'R');
          $this->SetX($this->lMargin);
          $this->Cell(0, $this->template->getLineHeight(), $this->invoice->getName(), 0, 0, 'L');
        } // if
      } // if

    } // Footer
    
  } // InvoiceTCPDF