<?php

/**
 * Parser Exception
 *
 * @package Less
 * @subpackage exception
 */
class Less_Exception_Parser extends Exception {

	/**
	 * The current file
	 *
	 * @var Less_ImportedFile
	 */
	public $currentFile;

	/**
	 * The current parser index
	 *
	 * @var integer
	 */
	public $index;

	protected $input;

	protected $details = array();


	/**
	 * Constructor
	 *
	 * @param string $message
	 * @param Exception $previous Previous exception
	 * @param integer $index The current parser index
	 * @param Less_FileInfo|string $currentFile The file
	 * @param integer $code The exception code
	 */
	public function __construct( $message = null, Exception $previous = null, $index = null, $currentFile = null, $code = 0 ) {

		if ( PHP_VERSION_ID < 50300 ) {
			$this->previous = $previous;
			parent::__construct( $message, $code );
		} else {
			parent::__construct( $message, $code, $previous );
		}

		$this->currentFile = $currentFile;
		$this->index       = $index;

		$this->genMessage();
	}


	protected function getInput() {

		if ( ! $this->input && $this->currentFile && $this->currentFile['filename'] && file_exists( $this->currentFile['filename'] ) ) {
			global $wp_filesystem;
			$this->input = $wp_filesystem->get_contents( $this->currentFile['filename'] );
		}
	}



	/**
	 * Converts the exception to string
	 *
	 * @return string
	 */
	public function genMessage() {

		if ( $this->currentFile && $this->currentFile['filename'] ) {
			$this->message .= ' in ' . basename( $this->currentFile['filename'] );
		}

		if ( $this->index !== null ) {
			$this->getInput();
			if ( $this->input ) {
				$line           = self::getLineNumber();
				$this->message .= ' on line ' . $line . ', column ' . self::getColumn();

				$lines = explode( "\n", $this->input );

				$count      = count( $lines );
				$start_line = max( 0, $line - 3 );
				$last_line  = min( $count, $start_line + 6 );
				$num_len    = strlen( $last_line );
				for ( $i = $start_line; $i < $last_line; $i++ ) {
					$this->message .= "\n" . str_pad( $i + 1, $num_len, '0', STR_PAD_LEFT ) . '| ' . $lines[ $i ];
				}
			}
		}

	}

	/**
	 * Returns the line number the error was encountered
	 *
	 * @return integer
	 */
	public function getLineNumber() {
		if ( $this->index ) {
			return substr_count( $this->input, "\n", 0, $this->index ) + 1;
		}
		return 1;
	}


	/**
	 * Returns the column the error was encountered
	 *
	 * @return integer
	 */
	public function getColumn() {

		$part = substr( $this->input, 0, $this->index );
		$pos  = strrpos( $part, "\n" );
		return $this->index - $pos;
	}

}
