<?php
namespace App\Service;

use Carbon\Carbon;

class Replacer
{
	public function replace($line, $data)
	{
		$instructions = $this->parseLine($line);
		
		$output = $line;
		foreach ($instructions as $instruction) {
			$output = str_replace($instruction['original'], $this->buildLine($instruction['instruction'], $data), $output);
		}
		return $output;
	}
	protected function parseLine($line)
	{
		$ini_el = '[[';
		$end_el = ']]';
		
		$instructions = [];
		$offset = 0;
		while (strpos($line, $ini_el, $offset) !== false) {
			$ini = strpos($line, $ini_el, $offset) + strlen($ini_el);
			$end = strpos($line, $end_el, $offset);
			$find = substr($line, $ini, $end - $ini);
			$instructions []= ['original' => $ini_el . $find . $end_el, 'instruction' => $find];
			$offset = $end + 1;
		}
		return $instructions;
	}
	protected function buildLine($instructions, $data)
	{
		if (strpos($instructions, '|') !== false) {
			$instructions = explode('|', $instructions);
		} else {
			$instructions = [$instructions];
		}
		$output = '';
		foreach ($instructions as $instruction) {
			$output = $this->buildReplace($instruction, $data, $output);
		}
		return $output;
	}
	protected function buildReplace($instruction, $data, $output = null)
	{
		if (strpos($instruction, '(') !== false) {
			$ini = strpos($instruction, '(') + 1;
			$end = strpos($instruction, ')');
			$mod = substr($instruction, $ini, $end - $ini);
			$instruction = substr($instruction, 0, $ini - 1);
		}
		switch ($instruction) {
			case 'UPPER':
				return strtoupper($output);
			case 'LOWER':
				return strtolower($output);
			case 'ISSET':
				if ($output != '') {
					return ', ' . $output;
				}
				return '';
			case 'UFS':
				return format('ufs', $output);
			case 'PESOS':
				return format('pesos', $output);
		}
		
		if (isset($mod)) {
			$obj = $this->find($instruction . '(' . $mod .')', $data);
		} else {
			$obj = $this->find($instruction, $data);
		}
		if ($obj) {
			return $obj;
		}
		if (is_object($output) and method_exists($output, $instruction)) {
			if (isset($mod)) {
				return $output->$instruction($mod);
			}
			return $output->$instruction();
		}
		if (is_object($output) and isset($output->$instruction)) {
			return $output->$instruction;
		}
		if ($instruction == 'strftime') {
			setlocale(LC_TIME, 'es-CL', 'es');
			$f = Carbon::parse($output, config('app.timezone'));
			$output = strftime($mod, $f->timestamp);
			return $output;
		}
		
		d($output, $instruction, function_exists($instruction), is_object($output), is_object($output) and isset($output->$instruction));
	}
	protected function find($instruction, $data)
	{
		if (strpos($instruction, '(') !== false) {
			$ini = strpos($instruction, '(') + 1;
			$end = strpos($instruction, ')');
			$mod = substr($instruction, $ini, $end - $ini);
			$instruction = substr($instruction, 0, $ini - 1);
		}
		if (method_exists($data, $instruction)) {
			if (isset($mod)) {
				return $data->$instruction($mod);
			}
			return $data->$instruction();
		}
		if (isset($data->$instruction)) {
			return $data->$instruction;
		}
		switch ($instruction) {
			case 'Unidades':
				$str = 'Departamento ' . $data->reserva()->unidad()->numeracion;
				foreach ($data->reserva()->unidades() as $unidad) {
					$str .= ', ' . ucwords($unidad->unidadProyecto()->tipo()->descripcion) . ' ' . $unidad->numeracion;
				}
				return $str;
			case 'inmobiliaria':
				return $data->proyecto()->inmobiliaria();
		}
		return false;
	}
}
?>