@*--<?php
require_once('Transformers.php');

class StylesBuilderCallbacksHelper
{
      private $_args;
      
      public function __construct($args = array())
      {
            $this->_args = $args;
      }
      
      public function mapParseSelector($value) 
      { 
          return trim($value);
      }
      
      public function filterParseProperties($value)
      { 
          return '' !== trim($value); 
      }
      
      public function reduceParseProperties($result, $value)
      {
          $parts = explode(':', $value);
          if (2 === count($parts)) {
                $propertyName = trim($parts[0]);
                $propertyValue = trim($parts[1]);
                if (isset($result[$propertyName])) {
                    $currentValue = $result[$propertyName];
                    if (is_array($currentValue)) {
                        array_push($currentValue, $propertyValue);
                    } else {
                        $currentValue = array($currentValue, $propertyValue);
                    }
                    $propertyValue = $currentValue;
                }
                $result[$propertyName] = $propertyValue;
          }
          return $result;
      }
      
      public function filterGet($value) 
      {
          $str = implode(', ', $value->selectors);
          return $this->_args['precision'] ? $this->_args['criteria'] === $str : 
              false !== strpos($str, $criteria);
      }
      
      public function filterStylesheet($value)
      {
            return count($value->selectors) > 0 &&
                count($value->properties) > 0;
      }
      
      public function reduceStylesheet($result, $value)
      {
           if ('' !== $value->parent) {
                array_push($result, $value->parent . " {\r\n"); 
           }
           array_push($result, implode(', ', $value->selectors));
           array_push($result, '{');
           foreach($value->properties as $property => $data) {
               if (is_string($data)) {
                    $data = array($data);
               }
               foreach($data as $style) {
                  array_push($result, '  ' .  $property . ': ' . $style . ';');
               }
           }
           array_push($result, "}\r\n");
           if ('' !== $value->parent) {
               array_push($result, "}\r\n");
           }
           return $result;
      }
}

class CssParser 
{
    private $_result = array();
    
    public function parse($content) 
    {
        $clearedContent = $this->clearContent($content);
        $offset = 0;
        
        // parse media rules
        while(false !== $mediaPos = strpos($clearedContent, '@media', 0)) {
            if (false !== $mediaPos) {
                $mediaOpenBracketPos = strpos($clearedContent, '{', $mediaPos);
                $start = $mediaOpenBracketPos;
                while(true) {
                    $openBracketPos = strpos($clearedContent, '{', $start + 1);
                    $closeBracketPos = strpos($clearedContent, '}', $start + 1);

                    if ((false === $openBracketPos && false !== $closeBracketPos) || $closeBracketPos < $openBracketPos) {
                        $mediaCloseBracketPos = $closeBracketPos;
                        break;
                    } else {
                        $start = $closeBracketPos;
                    }
                }
                $rules = substr($clearedContent, $mediaOpenBracketPos + 1, $mediaCloseBracketPos - ($mediaOpenBracketPos + 1));
                $parent = substr($clearedContent, $mediaPos, $mediaOpenBracketPos);
                $this->matchRules($rules, $this->_result, $parent);
                $clearedContent = substr_replace($clearedContent, '', $mediaPos, $mediaCloseBracketPos + 1);
            } 
        }
            
        $this->matchRules($clearedContent, $this->_result);

        return $this->_result;
    }

    private function matchRules($content, &$result, $parent = '') 
    {
        while (preg_match('/([^{]+)\s*\{\s*([^}]+)\s*\}/', $content, $matches, PREG_OFFSET_CAPTURE, $offset)) {
            $offset = $matches[0][1] + strlen($matches[0][0]);
            $item = new stdClass();
            $item->selectors = $this->parseSelector($matches[1][0]);
            $item->properties = $this->parseProperties($matches[2][0]);
            $item->parent = $parent;
            $result[] = $item;
        }
    }
  
    public function getStylesheet() 
    {
        return $this->_result; 
    }
    
    public function getRule($criteria, $precision = true, $all = false) 
    {
      $items = array_filter($this->_result, array(
          new StylesBuilderCallbacksHelper(array('criteria' => $criteria, 
              'precision' => $precision)), 'filterGet'
      ));  
      return (0 === count($items)) ? null : ($all ? $items : $items[0]);
    }
  
    public function setRule($rule, $property, $value) 
    {
        if (is_object($rule)) {
            $rule->properties[$property] = $value;
        }
    }
  
    private function clearContent($content)
    {
        $result = preg_replace('/\/\* Begin Additional CSS Styles \*\/([\s\S]*)\/\* End Additional CSS Styles \*\//', '', $content);
        $result = preg_replace('/\/\*[^\/]*\*\//', '', $result);
        $result = preg_replace('/#marker[^}]+}/', '', $result);
        return $result;
    }

    private function parseSelector($selector) 
    {
        $parts = explode(',', $selector);
        return array_map(array(new StylesBuilderCallbacksHelper(), 'mapParseSelector'), $parts);
    }
  
    private function parseProperties($properties) 
    {
        $propsArray = explode(';', $properties);
        return array_reduce(array_filter($propsArray, 
            array(new StylesBuilderCallbacksHelper(), 'filterParseProperties')), 
                array(new StylesBuilderCallbacksHelper(), 'reduceParseProperties'), array());
    }
}

class CssPrinter 
{
    public function printing($stylesheet) {

        if (is_string($stylesheet)) {
            return $stylesheet;
        }
        $result = array_reduce(array_filter($stylesheet, 
            array(new StylesBuilderCallbacksHelper(), 'filterStylesheet')), 
                array(new StylesBuilderCallbacksHelper(), 'reduceStylesheet'), array());
        return implode("\r\n", $result);
    }
}

class StylesBuilder
{
    public static function getCssParser()
    {
        return new CssParser();
    }
    
    public static function getCssPrinter()
    {
        return new CssPrinter();
    }
    
    public static function getEditorCssTransformer()
    {
        return new EditorCssTransformer();
    }
    
    public static function getPrintCssTransformer()
    {
        return new PrintCssTransformer();
    }
    
    public static function buildCssFiles($content)
    {
        $stylesheet = StylesBuilder::getCssParser()->parse($content);
        $printer    = StylesBuilder::getCssPrinter();
        
        $printCss = $printer->printing(StylesBuilder::getPrintCssTransformer()->transform($stylesheet));
        $editorCss = $printer->printing(StylesBuilder::getEditorCssTransformer()->transform($stylesheet));
        return array('print' => $printCss, 'editor' => $editorCss);
    }
}--*@