<?php

/**
 * CSSTidy - CSS Parser and Optimiser
 *
 * CSS Printing class
 * This class prints CSS data generated by csstidy.
 *
 * Copyright 2005, 2006, 2007 Florian Schmitz
 *
 * This file is part of CSSTidy.
 *
 *   CSSTidy 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.
 *
 *   CSSTidy 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 program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @license http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
 * @package csstidy
 * @author Florian Schmitz (floele at gmail dot com) 2005-2007
 * @author Brett Zamir (brettz9 at yahoo dot com) 2007
 * @author Cedric Morin (cedric at yterium dot com) 2010
 */

/**
 * CSS Printing class
 *
 * This class prints CSS data generated by csstidy.
 *
 * @package csstidy
 * @author Florian Schmitz (floele at gmail dot com) 2005-2006
 * @version 1.0.1
 */
class csstidy_print {

	/**
	 * Saves the input CSS string
	 * @var string
	 * @access private
	 */
	var $input_css = '';
	/**
	 * Saves the formatted CSS string
	 * @var string
	 * @access public
	 */
	var $output_css = '';
	/**
	 * Saves the formatted CSS string (plain text)
	 * @var string
	 * @access public
	 */
	var $output_css_plain = '';

	/**
	 * Constructor
	 * @param array $css contains the class csstidy
	 * @access private
	 * @version 1.0
	 */
	function csstidy_print(&$css) {
		$this->parser = & $css;
		$this->css = & $css->css;
		$this->template = & $css->template;
		$this->tokens = & $css->tokens;
		$this->charset = & $css->charset;
		$this->import = & $css->import;
		$this->namespace = & $css->namespace;
	}

	/**
	 * Resets output_css and output_css_plain (new css code)
	 * @access private
	 * @version 1.0
	 */
	function _reset() {
		$this->output_css = '';
		$this->output_css_plain = '';
	}

	/**
	 * Returns the CSS code as plain text
	 * @param string $default_media default @media to add to selectors without any @media
	 * @return string
	 * @access public
	 * @version 1.0
	 */
	function plain($default_media='') {
		$this->_print(true, $default_media);
		return $this->output_css_plain;
	}

	/**
	 * Returns the formatted CSS code
	 * @param string $default_media default @media to add to selectors without any @media
	 * @return string
	 * @access public
	 * @version 1.0
	 */
	function formatted($default_media='') {
		$this->_print(false, $default_media);
		return $this->output_css;
	}

	/**
	 * Returns the formatted CSS code to make a complete webpage
	 * @param string $doctype shorthand for the document type
	 * @param bool $externalcss indicates whether styles to be attached internally or as an external stylesheet
	 * @param string $title title to be added in the head of the document
	 * @param string $lang two-letter language code to be added to the output
	 * @return string
	 * @access public
	 * @version 1.4
	 */
	function formatted_page($doctype='xhtml1.1', $externalcss=true, $title='', $lang='en') {
		switch ($doctype) {
			case 'xhtml1.0strict':
				$doctype_output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
			"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
				break;
			case 'xhtml1.1':
			default:
				$doctype_output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
				"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
				break;
		}

		$output = $cssparsed = '';
		$this->output_css_plain = & $output;

		$output .= $doctype_output . "\n" . '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $lang . '"';
		$output .= ( $doctype === 'xhtml1.1') ? '>' : ' lang="' . $lang . '">';
		$output .= "\n<head>\n    <title>$title</title>";

		if ($externalcss) {
			$output .= "\n    <style type=\"text/css\">\n";
			$cssparsed = file_get_contents('cssparsed.css');
			$output .= $cssparsed; // Adds an invisible BOM or something, but not in css_optimised.php
			$output .= "\n</style>";
		} else {
			$output .= "\n" . '    <link rel="stylesheet" type="text/css" href="cssparsed.css" />';
//			}
		}
		$output .= "\n</head>\n<body><code id=\"copytext\">";
		$output .= $this->formatted();
		$output .= '</code>' . "\n" . '</body></html>';
		return $this->output_css_plain;
	}

	/**
	 * Returns the formatted CSS Code and saves it into $this->output_css and $this->output_css_plain
	 * @param bool $plain plain text or not
	 * @param string $default_media default @media to add to selectors without any @media
	 * @access private
	 * @version 2.0
	 */
	function _print($plain = false, $default_media='') {
		if ($this->output_css && $this->output_css_plain) {
			return;
		}

		$output = '';
		if (!$this->parser->get_cfg('preserve_css')) {
			$this->_convert_raw_css($default_media);
		}

		$template = & $this->template;

		if ($plain) {
			$template = array_map('strip_tags', $template);
		}

		if ($this->parser->get_cfg('timestamp')) {
			array_unshift($this->tokens, array(COMMENT, ' CSSTidy ' . $this->parser->version . ': ' . date('r') . ' '));
		}

		if (!empty($this->charset)) {
			$output .= $template[0] . '@charset ' . $template[5] . $this->charset . $template[6];
		}

		if (!empty($this->import)) {
			for ($i = 0, $size = count($this->import); $i < $size; $i++) {
				$import_components = explode(' ', $this->import[$i]);
				if (substr($import_components[0], 0, 4) === 'url(' && substr($import_components[0], -1, 1) === ')') {
					$import_components[0] = '\'' . trim(substr($import_components[0], 4, -1), "'\"") . '\'';
					$this->import[$i] = implode(' ', $import_components);
					$this->parser->log('Optimised @import : Removed "url("', 'Information');
				}
				$output .= $template[0] . '@import ' . $template[5] . $this->import[$i] . $template[6];
			}
		}

		if (!empty($this->namespace)) {
			if (substr($this->namespace, 0, 4) === 'url(' && substr($this->namespace, -1, 1) === ')') {
				$this->namespace = '\'' . substr($this->namespace, 4, -1) . '\'';
				$this->parser->log('Optimised @namespace : Removed "url("', 'Information');
			}
			$output .= $template[0] . '@namespace ' . $template[5] . $this->namespace . $template[6];
		}

		$output .= $template[13];
		$in_at_out = '';
		$out = & $output;

		foreach ($this->tokens as $key => $token) {
			switch ($token[0]) {
				case AT_START:
					$out .= $template[0] . $this->_htmlsp($token[1], $plain) . $template[1];
					$out = & $in_at_out;
					break;

				case SEL_START:
					if ($this->parser->get_cfg('lowercase_s'))
						$token[1] = strtolower($token[1]);
					$out .= ( $token[1]{0} !== '@') ? $template[2] . $this->_htmlsp($token[1], $plain) : $template[0] . $this->_htmlsp($token[1], $plain);
					$out .= $template[3];
					break;

				case PROPERTY:
					if ($this->parser->get_cfg('case_properties') === 2) {
						$token[1] = strtoupper($token[1]);
					} elseif ($this->parser->get_cfg('case_properties') === 1) {
						$token[1] = strtolower($token[1]);
					}
					$out .= $template[4] . $this->_htmlsp($token[1], $plain) . ':' . $template[5];
					break;

				case VALUE:
					$out .= $this->_htmlsp($token[1], $plain);
					if ($this->_seeknocomment($key, 1) == SEL_END && $this->parser->get_cfg('remove_last_;')) {
						$out .= str_replace(';', '', $template[6]);
					} else {
						$out .= $template[6];
					}
					break;

				case SEL_END:
					$out .= $template[7];
					if ($this->_seeknocomment($key, 1) != AT_END)
						$out .= $template[8];
					break;

				case AT_END:
					$out = & $output;
					$out .= $template[10] . str_replace("\n", "\n" . $template[10], $in_at_out);
					$in_at_out = '';
					$out .= $template[9];
					break;

				case COMMENT:
					$out .= $template[11] . '/*' . $this->_htmlsp($token[1], $plain) . '*/' . $template[12];
					break;
			}
		}

		$output = trim($output);

		if