<?php

/**

 * PHPExcel

 *

 * Copyright (c) 2006 - 2014 PHPExcel

 *

 * This library is free software; you can redistribute it and/or

 * modify it under the terms of the GNU Lesser General Public

 * License as published by the Free Software Foundation; either

 * version 2.1 of the License, or (at your option) any later version.

 *

 * This library is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 * Lesser General Public License for more details.

 *

 * You should have received a copy of the GNU Lesser General Public

 * License along with this library; if not, write to the Free Software

 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

 *

 * @category   PHPExcel

 * @package    PHPExcel_Writer_Excel5

 * @copyright  Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)

 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL

 * @version    ##VERSION##, ##DATE##

 */





/**

 * PHPExcel_Shared_Escher_DggContainer_BstoreContainer

 *

 * @category   PHPExcel

 * @package    PHPExcel_Writer_Excel5

 * @copyright  Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)

 */

class PHPExcel_Writer_Excel5_Escher

{

	/**

	 * The object we are writing

	 */

	private $_object;



	/**

	 * The written binary data

	 */

	private $_data;



	/**

	 * Shape offsets. Positions in binary stream where a new shape record begins

	 *

	 * @var array

	 */

	private $_spOffsets;



	/**

	 * Shape types.

	 *

	 * @var array

	 */

	private $_spTypes;

	

	/**

	 * Constructor

	 *

	 * @param mixed

	 */

	public function __construct($object)

	{

		$this->_object = $object;

	}



	/**

	 * Process the object to be written

	 */

	public function close()

	{

		// initialize

		$this->_data = '';



		switch (get_class($this->_object)) {



		case 'PHPExcel_Shared_Escher':

			if ($dggContainer = $this->_object->getDggContainer()) {

				$writer = new PHPExcel_Writer_Excel5_Escher($dggContainer);

				$this->_data = $writer->close();

			} else if ($dgContainer = $this->_object->getDgContainer()) {

				$writer = new PHPExcel_Writer_Excel5_Escher($dgContainer);

				$this->_data = $writer->close();

				$this->_spOffsets = $writer->getSpOffsets();

				$this->_spTypes = $writer->getSpTypes();

			}

			break;



		case 'PHPExcel_Shared_Escher_DggContainer':

			// this is a container record



			// initialize

			$innerData = '';



			// write the dgg

			$recVer			= 0x0;

			$recInstance	= 0x0000;

			$recType		= 0xF006;



			$recVerInstance  = $recVer;

			$recVerInstance |= $recInstance << 4;



			// dgg data

			$dggData =

				pack('VVVV'

					, $this->_object->getSpIdMax() // maximum shape identifier increased by one

					, $this->_object->getCDgSaved() + 1 // number of file identifier clusters increased by one

					, $this->_object->getCSpSaved()

					, $this->_object->getCDgSaved() // count total number of drawings saved

				);



			// add file identifier clusters (one per drawing)

			$IDCLs = $this->_object->getIDCLs();



			foreach ($IDCLs as $dgId => $maxReducedSpId) {

				$dggData .= pack('VV', $dgId, $maxReducedSpId + 1);

			}



			$header = pack('vvV', $recVerInstance, $recType, strlen($dggData));

			$innerData .= $header . $dggData;



			// write the bstoreContainer

			if ($bstoreContainer = $this->_object->getBstoreContainer()) {

				$writer = new PHPExcel_Writer_Excel5_Escher($bstoreContainer);

				$innerData .= $writer->close();

			}



			// write the record

			$recVer			= 0xF;

			$recInstance	= 0x0000;

			$recType		= 0xF000;

			$length			= strlen($innerData);



			$recVerInstance  = $recVer;

			$recVerInstance |= $recInstance << 4;



			$header = pack('vvV', $recVerInstance, $recType, $length);



			$this->_data = $header . $innerData;

			break;



		case 'PHPExcel_Shared_Escher_DggContainer_BstoreContainer':

			// this is a container record



			// initialize

			$innerData = '';



			// treat the inner data

			if ($BSECollection = $this->_object->getBSECollection()) {

				foreach ($BSECollection as $BSE) {

					$writer = new PHPExcel_Writer_Excel5_Escher($BSE);

					$innerData .= $writer->close();

				}

			}



			// write the record

			$recVer			= 0xF;

			$recInstance	= count($this->_object->getBSECollection());

			$recType		= 0xF001;

			$length			= strlen($innerData);



			$recVerInstance  = $recVer;

			$recVerInstance |= $recInstance << 4;



			$header = pack('vvV', $recVerInstance, $recType, $length);



			$this->_data = $header . $innerData;

			break;



		case 'PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE':

			// this is a semi-container record



			// initialize

			$innerData = '';



			// here we treat the inner data

			if ($blip = $this->_object->getBlip()) {

				$writer = new PHPExcel_Writer_Excel5_Escher($blip);

				$innerData .= $writer->close();

			}



			// initialize

			$data = '';



			$btWin32 = $this->_object->getBlipType();

			$btMacOS = $this->_object->getBlipType();

			$data .= pack('CC', $btWin32, $btMacOS);



			$rgbUid = pack('VVVV', 0,0,0,0); // todo

			$data .= $rgbUid;



			$tag = 0;

			$size = strlen($innerData);

			$cRef = 1;

			$foDelay = 0; //todo

			$unused1 = 0x0;

			$cbName = 0x0;

			$unused2 = 0x0;

			$unused3 = 0x0;

			$data .= pack('vVVVCCCC', $tag, $size, $cRef, $foDelay, $unused1, $cbName, $unused2, $unused3);



			$data .= $innerData;



			// write the record

			$recVer			= 0x2;

			$recInstance	= $this->_object->getBlipType();

			$recType		= 0xF007;

			$length			= strlen($data);



			$recVerInstance  = $recVer;

			$recVerInstance |=	$recInstance << 4;



			$header = pack('vvV', $recVerInstance, $recType, $length);



			$this->_data = $header;



			$this->_data .= $data;

			break;



		case 'PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip':

			// this is an atom record



			// write the record

			switch ($this->_object->getParent()->getBlipType()) {



			case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:

				// initialize

				$innerData = '';



				$rgbUid1 = pack('VVVV', 0,0,0,0); // todo

				$innerData .= $rgbUid1;



				$tag = 0xFF; // todo

				$innerData .= pack('C', $tag);



				$innerData .= $this->_object->getData();



				$recVer			= 0x0;

				$recInstance	= 0x46A;

				$recType		= 0xF01D;

				$length			= strlen($innerData);



				$recVerInstance  = $recVer;

				$recVerInstance |=	$recInstance << 4;



				$header = pack('vvV', $recVerInstance, $recType, $length);



				$this->_data = $header;



				$this->_data .= $innerData;

				break;



			case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:

				// initialize

				$innerData = '';



				$rgbUid1 = pack('VVVV', 0,0,0,0); // todo

				$innerData .= $rgbUid1;



				$tag = 0xFF; // todo

				$innerData .= pack('C', $tag);



				$innerData .= $this->_object->getData();



				$recVer			= 0x0;

				$recInstance	= 0x6E0;

				$recType		= 0xF01E;

				$length			= strlen($innerData);



				$recVerInstance  = $recVer;

				$recVerInstance |=	$recInstance << 4;



				$header = pack('vvV', $recVerInstance, $recType, $length);



				$this->_data = $header;



				$this->_data .= $innerData;

				break;



			}

			break;



		case 'PHPExcel_Shared_Escher_DgContainer':

			// this is a container record



			// initialize

			$innerData = '';



			// write the dg

			$recVer			= 0x0;

			$recInstance	= $this->_object->getDgId();

			$recType		= 0xF008;

			$length			= 8;



			$recVerInstance  = $recVer;

			$recVerInstance |= $recInstance << 4;



			$header = pack('vvV', $recVerInstance, $recType, $length);



			// number of shapes in this drawing (including group shape)

			$countShapes = count($this->_object->getSpgrContainer()->getChildren());

			$innerData .= $header . pack('VV', $countShapes, $this->_object->getLastSpId());

			//$innerData .= $header . pack('VV', 0, 0);



			// write the spgrContainer

			if ($spgrContainer = $this->_object->getSpgrContainer()) {

				$writer = new PHPExcel_Writer_Excel5_Escher($spgrContainer);

				$innerData .= $writer->close();



				// get the shape offsets relative to the spgrContainer record

				$spOffsets = $writer->getSpOffsets();

				$spTypes   = $writer->getSpTypes();

				

				// save the shape offsets relative to dgContainer

				foreach ($spOffsets as & $spOffset) {

					$spOffset += 24; // add length of dgContainer header data (8 bytes) plus dg data (16 bytes)

				}



				$this->_spOffsets = $spOffsets;

				$this->_spTypes = $spTypes;

			}



			// write the record

			$recVer			= 0xF;

			$recInstance	= 0x0000;

			$recType		= 0xF002;

			$length			= strlen($innerData);



			$recVerInstance  = $recVer;

			$recVerInstance |= $recInstance << 4;



			$header = pack('vvV', $recVerInstance, $recType, $length);



			$this->_data = $header . $innerData;

			break;



		case 'PHPExcel_Shared_Escher_DgContainer_SpgrContainer':

			// this is a container record



			// initialize

			$innerData = '';



			// initialize spape offsets

			$totalSize = 8;

			$spOffsets = array();

			$spTypes   = array();



			// treat the inner data

			foreach ($this->_object->getChildren() as $spContainer) {

				$writer = new PHPExcel_Writer_Excel5_Escher($spContainer);

				$spData = $writer->close();

				$innerData .= $spData;



				// save the shape offsets (where new shape records begin)

				$totalSize += strlen($spData);

				$spOffsets[] = $totalSize;

				

				$spTypes = array_merge($spTypes, $writer->getSpTypes());

			}



			// write the record

			$recVer			= 0xF;

			$recInstance	= 0x0000;

			$recType		= 0xF003;

			$length			= strlen($innerData);



			$recVerInstance  = $recVer;

			$recVerInstance |= $recInstance << 4;



			$header = pack('vvV', $recVerInstance, $recType, $length);



			$this->_data = $header . $innerData;

			$this->_spOffsets = $spOffsets;

			$this->_spTypes = $spTypes;

			break;



		case 'PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer':

			// initialize

			$data = '';



			// build the data



			// write group shape record, if necessary?

			if ($this->_object->getSpgr()) {

				$recVer			= 0x1;

				$recInstance	= 0x0000;

				$recType		= 0xF009;

				$length			= 0x00000010;



				$recVerInstance  = $recVer;

				$recVerInstance |= $recInstance << 4;



				$header = pack('vvV', $recVerInstance, $recType, $length);



				$data .= $header . pack('VVVV', 0,0,0,0);

			}

			$this->_spTypes[] = ($this->_object->getSpType());



			// write the shape record

			$recVer			= 0x2;

			$recInstance	= $this->_object->getSpType(); // shape type

			$recType		= 0xF00A;

			$length			= 0x00000008;



			$recVerInstance  = $recVer;

			$recVerInstance |= $recInstance << 4;



			$header = pack('vvV', $recVerInstance, $recType, $length);



			$data .= $header . pack('VV', $this->_object->getSpId(), $this->_object->getSpgr() ? 0x0005 : 0x0A00);





			// the options

			if ($this->_object->getOPTCollection()) {

				$optData = '';



				$recVer			= 0x3;

				$recInstance	= count($this->_object->getOPTCollection());

				$recType		= 0xF00B;

				foreach ($this->_object->getOPTCollection() as $property => $value) {

					$optData .= pack('vV', $property, $value);

				}

				$length			= strlen($optData);



				$recVerInstance  = $recVer;

				$recVerInstance |= $recInstance << 4;



				$header = pack('vvV', $recVerInstance, $recType, $length);

				$data .= $header . $optData;

			}



			// the client anchor

			if ($this->_object->getStartCoordinates()) {

				$clientAnchorData = '';



				$recVer			= 0x0;

				$recInstance	= 0x0;

				$recType		= 0xF010;



				// start coordinates

				list($column, $row) = PHPExcel_Cell::coordinateFromString($this->_object->getStartCoordinates());

				$c1 = PHPExcel_Cell::columnIndexFromString($column) - 1;

				$r1 = $row - 1;



				// start offsetX

				$startOffsetX = $this->_object->getStartOffsetX();



				// start offsetY

				$startOffsetY = $this->_object->getStartOffsetY();



				// end coordinates

				list($column, $row) = PHPExcel_Cell::coordinateFromString($this->_object->getEndCoordinates());

				$c2 = PHPExcel_Cell::columnIndexFromString($column) - 1;

				$r2 = $row - 1;



				// end offsetX

				$endOffsetX = $this->_object->getEndOffsetX();



				// end offsetY

				$endOffsetY = $this->_object->getEndOffsetY();



				$clientAnchorData = pack('vvvvvvvvv', $this->_object->getSpFlag(),

					$c1, $startOffsetX, $r1, $startOffsetY,

					$c2, $endOffsetX, $r2, $endOffsetY);

				

				$length			= strlen($clientAnchorData);



				$recVerInstance  = $recVer;

				$recVerInstance |= $recInstance << 4;



				$header = pack('vvV', $recVerInstance, $recType, $length);

				$data .= $header . $clientAnchorData;

			}



			// the client data, just empty for now

			if (!$this->_object->getSpgr()) {

				$clientDataData = '';



				$recVer			= 0x0;

				$recInstance	= 0x0;

				$recType		= 0xF011;



				$length = strlen($clientDataData);



				$recVerInstance  = $recVer;

				$recVerInstance |= $recInstance << 4;



				$header = pack('vvV', $recVerInstance, $recType, $length);

				$data .= $header . $clientDataData;

			}



			// write the record

			$recVer			= 0xF;

			$recInstance	= 0x0000;

			$recType		= 0xF004;

			$length			= strlen($data);



			$recVerInstance  = $recVer;

			$recVerInstance |= $recInstance << 4;



			$header = pack('vvV', $recVerInstance, $recType, $length);



			$this->_data = $header . $data;

			break;



		}



		return $this->_data;

	}



	/**

	 * Gets the shape offsets

	 *

	 * @return array

	 */

	public function getSpOffsets()

	{

		return $this->_spOffsets;

	}



	/**

	 * Gets the shape types

	 *

	 * @return array

	 */

	public function getSpTypes()

	{

		return $this->_spTypes;

	}

	

	

}

