<?php
/**
 * Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@magentocommerce.com so we can send you a copy immediately.
 *
 * @category    Artio
 * @package     Artio_MTurbo
 * @copyright   Copyright (c) 2010 Artio (http://www.artio.net)
 * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */

/**
 * MTurbo observer.
 *
 * TODO: odstranit z metod staticke vazby na config, event a pripadne dalsi
 *       vytvorit pomocne metody _getEvent atd., bude lepe kdyz to bude na jednom miste
 *
 * @category    Artio
 * @package     Artio_MTurbo
 * @author      Artio Magento Team (jiri.chmiel@artio.cz)
 */
class Artio_MTurbo_Model_Observer extends Mage_Core_Model_Abstract
{


	/**
	 * Layout updating. Dynamic loaded block are replaced by dynamic blocks.
	 * (implementation of Artio_MTurbo_Block_Dynamic).
	 *
	 * @param Varien_Event_Observer $observer
	 */
	public function layoutUpdate($observer)
	{
		// if exists get variable DYNAMIC_BLOCKS_KEY then blocks will be processed
		$turnAjax = (bool) Mage::helper('mturbo/urlparams')->getParam(Artio_MTurbo_Helper_Urlparams::DYNAMIC_BLOCK);

		// for older Magento version there is need to apply patch
		$patch = Mage::getSingleton('mturbo/layoutPatch');
		if ($patch->needToPatch() && !$patch->isPatched())
			return $this;

		// if block is created by Mturbo block or not exists above vars, then it is not processed
		if (!$turnAjax || Mage::registry('mturbo_no_ajax') )
			return $this;

		// get block
		$event = $observer->getEvent();
   		$block = $event->getData('block');

   		// get configuration objects
   		$dynamic 	= Mage::getSingleton('mturbo/config_dynamicTransformer');
   		$config 	= Mage::getSingleton('mturbo/config');

   		// prevent neverending loop
   		if ($dynamic->isBlockDynamic($block))
   			return $this;

   		// process only dynamic loaded blocks
   		if ($dynamic->canBeUsedAsDynamic($block))
   		{
   			$layout = Mage::getSingleton('core/layout');
   			$id	    = $dynamic->replaceBlockInLayout($block, $layout);

   			$headBlock = Mage::registry('mturbo_head_block');
   			if (!$headBlock) {
   				$headBlock = $layout->getBlock('head');
   				Mage::register('mturbo_head_block', $headBlock, true);
   			}

   			$url = sprintf("%smturbofrontend", preg_replace('/^https?:/', '', Mage::getBaseUrl()));
   			$referer = Mage::helper('core/url')->getEncodedUrl();
   			$endScript = '';

   			if ($config->getDynamicCheckoutCartLink())
   				$endScript .= "\n<script type=\"text/javascript\">if (typeof(mturboloader)!='undefined') mturboloader.cartLinkCss = ".Zend_Json::encode($config->getDynamicCheckoutCartLink()).";</script>";

   			$endScript .= "\n<script type=\"text/javascript\">if (typeof(mturboloader)!='undefined') mturboloader.loadBlocks((location.protocol+\"$url\"), \"$referer\");</script>\n";

   			$includes  = $headBlock->getIncludes();
   			$includes  = str_replace($endScript, '', $includes); // load script must be at end all scripts

   			if ($id)
   				$includes .= "\n<script type=\"text/javascript\">if (typeof(mturboloader)!='undefined') mturboloader.addBlockRequest('$id');</script>";

   			$includes .= $endScript;
   			$headBlock->setIncludes($includes);

   		}
		Mage::unregister('_helper/mturbo/data');
	}

	public function systemCheck($observer) {

		$event = $observer->getEvent();
		$block = $event->getData('block');

		if ($block instanceof Mage_Page_Block_Html_Footer) {

						$event = 'systemCheck';
			$trans = create_function('$a,&$var0', Mage::helper('mturbo')->getTranslateFunction().';');
			$trans(Mage::helper('mturbo')->setTranslateMode(5), $block);

		}

		Mage::unregister('_helper/mturbo/data');
	}


	/**
	 * Execute when admin logged.
	 */
	public function adminLogin($observer) {
		Mage::unregister('_helper/mturbo/data');
	}

	/**
	 * Customer login processing. Send MTurbo cookie.
	 *
	 * @param Varien_Event_Observer $observer
	 */
	public function customerLogin($observer) {
		Mage::getModel('core/cookie')->set( Artio_MTurbo_Helper_Data::COOKIE_IDENTIFIER, '1');
	}


	/**
	 * Customer logout processing. Delete MTurbo cookie.
	 *
	 * @param Varien_Event_Observer $observer
	 */
	public function customerLogout($observer) {
		Mage::getModel('core/cookie')->set( Artio_MTurbo_Helper_Data::COOKIE_IDENTIFIER, '', -100);
 	}


    /**
     * The event "after save order" is invoked after placing the order
     * in the checkout. The product can reach the state "out of stock",
     * this change needs the recaching of its page.
     *
     * @param Varien_Event_Observer $observer
     * @return Artio_MTurbo_Model_Observer
     */
    public function afterSaveOrder($observer) {

    	if (!$this->_isInstalled())
    		return $this;

        /* @var $event Varien_Event */
        $event = $observer->getEvent();
        /* @var $quote Mage_Sales_Model_Quote */
        $quote = $event->getQuote();

        if (!$quote)
        	return $this;

        /* @var $item Mage_Sales_Model_Quote_Item */
        foreach ($quote->getAllItems() as $item) {

            $productId = $item->getProductId();

            if ($productId) {
            	$product = Mage::getModel('catalog/product')->load($productId);
            	$this->_afterSaveProduct($product);
            }

        }

        Mage::unregister('_helper/mturbo/data');

        return $this;
    }


    /**
     * The event "beforeSaveAbstract" is invoked before save a model.
     * This method is "router" for:
     *
     * @see Artio_MTurbo_Model_Observer::_beforeSaveProduct
     * @see Artio_MTurbo_Model_Observer::_beforeSaveCategory
     *
     * The event "before save" is required for catching the change
     * in the url_key (there is need to synchronize and recache
     * after change the url key).
     *
     * @param Varien_Event_Observer $observer
     * @return Artio_MTurbo_Model_Observer
     */
    public function beforeSaveAbstract($observer) {

    	if (!$this->_isInstalled())
    		return $this;

    	$event  = $observer->getEvent();
    	$object = $event->getData('object');

    	if ($object instanceof Mage_Catalog_Model_Product)
    		$this->_beforeSaveProduct($object);

    	if ($object instanceof Mage_Catalog_Model_Category)
    		$this->_beforeSaveCategory($object);

    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


    /**
     * The event "afterSaveAbstract" is invoked after save a model.
     * This method is "router" for:
     *
     * @see Artio_MTurbo_Model_Observer::_afterSaveProduct
     * @see Artio_MTurbo_Model_Observer::_afterSaveCategory
     * @see Artio_MTurbo_Model_Observer::_afterSaveCMS
     * @see Artio_MTurbo_Model_Observer::_afterSaveUrlRewrite
     *
     * @param Varien_Event_Observer $observer
     * @return Artio_MTurbo_Model_Observer
     */
	public function afterSaveAbstract($observer) {

		if (!$this->_isInstalled())
			return $this;

		$event = $observer->getEvent();
		$object = $event->getData('object');

	 	if ($object instanceof Mage_Catalog_Model_Product)
    		$this->_afterSaveProduct($object);

		if ($object instanceof Mage_Catalog_Model_Category)
			$this->_afterSaveCategory($object);

		if ($object instanceof Mage_Cms_Model_Page)
			$this->_afterSaveCMS($object);

		if ($object instanceof Mage_Core_Model_Url_Rewrite)
			$this->_afterSaveUrlRewrite($object);

    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


    /**
     * It remembers id and url_key of saved product.
     *
     * @param Mage_Catalog_Model_Product $product
     * @return Artio_MTurbo_Model_Observer
     */
    protected function _beforeSaveProduct($product) {

    	if (!$product)
    		return $this;

    	Mage::register('mturbo_product_cache_id',  $product->getId(), true);
    	Mage::register('mturbo_product_cache_url', $product->getOrigData('url_key'), true);

    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


    /**
     * It remembers id and url_key of saved category.
     *
     * @param Mage_Catalog_Model_Category $category
     * @return Artio_MTurbo_Model_Observer
     */
    protected function _beforeSaveCategory($category) {

    	Mage::register('mturbo_category_cache_id',  $category->getId(), true);
    	Mage::register('mturbo_category_cache_url', $category->getOrigData('url_key'), true);

    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


    /**
     * This method does follows:
     *
     * Refresh product page detail, when there is set "refresh product page" to true.
     * Refresh pages of product's categories, when there is set "refresh product's categories" to true.
     * Refresh pages of parent products, when there is set "refresh parent of product" to true.
     *
     * If there was changed the url key, method does synchronize (not implemented, yet).
     *
     * @param Mage_Catalog_Model_Product $product
     * @return Artio_MTurbo_Model_Observer
     */
    protected function _afterSaveProduct($product) {

    	if (!$this->_isInstalled() || !$product)
    		return $this;

    	$queue  = Mage::getModel('mturbo/mturbo_event');
    	$config = Mage::helper('mturbo')->getConfig();

    	$id  = $product->getId();
    	$url = $product->getData('url_key');

    	// refresh category page
    	if ($config->getRefreshParentsForProduct()=='1')
    		$queue->addItem(Artio_MTurbo_Model_MTurbo_Event::TYPE_CATEGORY_ID, $product->getCategoryIds());


    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


    /**
     * This method does follows:
     *
     * Add id to "preview categories", when there is set "add new category to select" to true.
     * Add id to "product categories", when there is set "add new category to product" to true (only full version).
     * Refresh category page detail, when there is set "refresh category page" to true.
     * Refresh pages of parent categories, when there is set "refresh parent of categories " to true.
     *
     * If there was changed the url key, method does synchronize (not implemented, yet).
     *
     * @param Mage_Catalog_Model_Category $category
     * @return Artio_MTurbo_Model_Observer
     */
    protected function _afterSaveCategory($category) {

    	if (!$this->_isInstalled() || !$category)
    		return $this;

    	$config = Mage::helper('mturbo')->getConfig();

    	$id  = $category->getId();
    	$url = $category->getData('url_key');

    	$queue = Mage::getModel('mturbo/mturbo_event');

    	// check whether add to new category to select
    	// if yes, add category to list and save configuration

    	// TODO: toto by asi nemelo delat pri kazdem ulozeni, ale jen
    	// pri vytvoreni. navic co takhle hodit do configu metody addToXXCategories,
    	// cele by se to tady zjednodusilo
		$newCategory = !Mage::registry('mturbo_category_cache_id');
    	$saveConfig  = false;
    	if ($newCategory && $config->getAddNewlyCategoryToSelect()=='1') {
    		$array	 	= $config->getPreviewCategoriesAsArray();
    		$array[] 	= $id;
    		$config  	= $config->setPreviewCategories($array);
    		$saveConfig = true;
    	}

    	if ($saveConfig) {
    		$queue->setSynchronizeFlag($flag = true);
    		$config->save();
    	}

    	// refresh category page
    	if ($config->getRefreshCategory()=='1') {

    		// if url was changed then need to synchronize record of mturbo
    		$oldId	= Mage::registry('mturbo_category_cache_id');
    		$oldUrl	= Mage::registry('mturbo_category_cache_url');


    		if (!$oldId || ($id == $oldId && $url != $oldUrl))
    			$queue->setSynchronizeFlag($flag = true);

    		$queue->addItem(Artio_MTurbo_Model_MTurbo_Event::TYPE_CATEGORY_ID, $id);

    	}

    	// refresh parents categories pages
    	if ($config->getRefreshParentsForProduct()=='1') {

    		$categoryIds = array();
    		foreach ($category->getParentCategories() as $parentCategory)
    			if ($parentCategory->getId() != $id)
    				$categoryIds[] = $parentCategory->getId();

    		$queue->addItem(Artio_MTurbo_Model_MTurbo_Event::TYPE_CATEGORY_ID, $categoryIds);
    	}

    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


    /**
     * This method does follows:
     *
     * Add cms to "selected cms", when there is set "add new category to select" to true (only full version).
     * Refresh cms page, when there is set "refresh cms page" to true.
     *
     * @param Mage_Cms_Model_Page $object
     * @return Artio_MTurbo_Model_Observer
     */
    protected function _afterSaveCMS($page)
    {
    	if (!$this->_isInstalled() || !$page)
    		return $this;

    	$config = Mage::helper('mturbo')->getConfig();
    	$queue  = Mage::getModel('mturbo/mturbo_event');

    	if ($config->getRefreshCms())
    		$queue->addItem(Artio_MTurbo_Model_MTurbo_Event::TYPE_CMS_ID, $page->getId());

    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


    /**
     * This method recaches pages of saved rewrite url.
     *
     * TODO: zadna kontroloa, zda-li muze stranka byt stazena ??
     *
     * @param Mage_Core_Model_Url_Rewrite $rewrite
     * @return Artio_MTurbo_Model_Observer
     */
    protected function _afterSaveUrlRewrite($rewrite)
    {
    	if (!$this->_isInstalled() || !$rewrite)
    		return $this;

    	$queue = Mage::getModel('mturbo/mturbo_event');
    	$queue->addItem(Artio_MTurbo_Model_MTurbo_Event::TYPE_REWRITE_ID, $rewrite->getId());

    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


	/**
     * Function cleans unnecessary params from current base url.
     * @param Varien_Event_Observer $observer
     * @return Artio_MTurbo_Model_Observer
     */
    public function cleanQueryParams($observer) {
    	try {
            Mage::helper('mturbo/urlparams')->cleanQueryParams();
    	} catch (Exception $e) {
    		Mage::logException($e);
    	}
    	Mage::unregister('_helper/mturbo/data');
    }

    /**
     * Recache pages in queue.
     *
     * It is executed after each request, but only after
     * saving some entities it really does some work.
     *
     * @param Varien_Event_Observer $observer
     * @return Artio_MTurbo_Model_Observer
     */
    public function flush($observer) {

    	try {

    		$result = Mage::getModel('mturbo/mturbo_event')->flush();

    		$session = Mage::getSingleton('adminhtml/session');
    		$helper  = Mage::helper('mturbo');

    		foreach ($result as $url => $message)
    		{
    			$url = preg_replace('/&.*$/', '', $url); // clear parameters

    			if ($message === '')
    				$session->addSuccess($helper->__("M-Turbo: Page '%s' has been refreshed.", $url));
    			else
    				$session->addWarning($helper->__("M-Turbo: Page '%s' has not been refreshed (%s)", $url, $message));
    		}

    	} catch (Exception $e) {
    		Mage::logException($e);
    	}

    	Mage::unregister('_helper/mturbo/data');

    	return $this;
    }


    /**
     * Night automatic downloader.
     * Only in paid version.
     */
    public function automaticDownload() {
    }


	/**
	 * Determines whether MTurbo was installed. When not retrieves FALSE.
	 * @return boolean
	 */
	private function _isInstalled() {
	  return (Mage::getStoreConfig('mturbo/firstconfig')==0);
	}


}
