<?php
namespace Models;
use Mike42\Escpos\PrintConnectors\FilePrintConnector;
use Mike42\Escpos\PrintConnectors\NetworkPrintConnector;
use Mike42\Escpos\PrintConnectors\WindowsPrintConnector;
use Mike42\Escpos\Printer;
use Mike42\Escpos\CapabilityProfile;

class escpos_Fr_php {
	public $f3, $sets, $config, $connector, $printer, $check_sum;
	
	function __construct($f3, $sets, $config) {
		$this->f3=$f3;
		$this->sets=$sets;
		//$this->config=parse_ini_file($sets['driver'].'/server.config'); // Настройки драйвера
		$this->config=$config;
		if(!isset($this->config['TallFont'])) {
			$this->config['TallFont']=1;
		}
		if(!isset($this->config['WideFont'])) {
			$this->config['WideFont']=1;
		}
		spl_autoload_register(function ($class_name) {
    		require_once('src/'.str_replace('\\', '/', $class_name).'.php');
		});
		if($this->config['AlwaysExec']) {
			$this->always_exec($this->config['AlwaysExec']);
		}
	}

	function printer_connect() {
		$this->config['PortType']=mb_strtolower($this->config['PortType']);
		if($this->config['PortType']=='local') {
			return $connector = new FilePrintConnector($this->sets['url']);
		}
		elseif($this->config['PortType']=='remote') {
			$u=mb_substr($this->sets['url'], mb_strrpos($this->sets['url'], '/')+1);
			$url=explode(':', $u);
			$host = $url[0];
			$port = $url[1];
			return $connector = new NetworkPrintConnector($host, $port);
		}
		elseif($this->config['PortType']=='windowsusb') {
			return $connector = new WindowsPrintConnector($this->sets['url']);
		}

		$error_txt='Невозможно установить соединение. Проверьте включен ли кассовый аппарат и/или проверьте провод от аппарата до компьютера. Попробуйте выключить и включить кассовый аппарат.';
		$this->f3->get('logs_model')->save_log($error_txt.' (Касса)', 'error');
		if($this->f3->get('fr_error_ignore')) {
            return array(
          	    'success'=>false,
                'error'=>$error_txt
            );
        }
		echo '<p class="false">'.$error_txt.'</p>';
		exit();
	}

	function always_exec($exec) {
		if(!is_array($exec) || empty($exec)) return;
		foreach ($exec as $cmd) {
			if($cmd!='') {
				exec($cmd);
			}
		}
	}

	function kkm_init() {
		if(isset($this->config['Exec']) && is_array($this->config['Exec']) && !empty($this->config['Exec'])) {
            foreach ($this->config['Exec'] as $cmd) {
                if($cmd!='') {
                    exec($cmd);
                }
            }
        }
        if(isset($this->config['Send']) && is_array($this->config['Send']) && !empty($this->config['Send'])) {
        	$connector = $this->printer_connect();
        	if(!$connector) {
        		$error_txt='Невозможно установить соединение. Проверьте включен ли кассовый аппарат и/или проверьте провод от аппарата до компьютера. Попробуйте выключить и включить кассовый аппарат.';
				$this->f3->get('logs_model')->save_log($error_txt.' (Касса)', 'error');
				if($this->f3->get('fr_error_ignore')) {
                  return array(
                    'success'=>false,
                    'error'=>$error_txt
                  );
              	}
				echo '<p class="false">'.$error_txt.'</p>';
				exit();
        	}
			$this->printer = new Printer($connector);
            foreach ($this->config['Send'] as $cmd) {
                if(!$cmd) continue;
                $p=explode(';', $cmd);
                if(count($p)>1) {
                	$connector->write(Printer::ESC .$p[0]. chr($p[1]));
                }
                else {
                	$connector->write(pack('H*', $cmd));
                }
            }
            $this->printer->close();
        }
       	$this->f3->set('COOKIE.'.$this->sets['printer'].'_drivers_init', 1);
	}

	// Форматирование текста
	function text_format($s, $w=48) {
        $s=str_replace('#kkm_bold#', '', $s);
        // Заменяем #kkm_right# на пробелы
        $kkm_right="#kkm_right#"; # тэг сдвига вправо
        $space_n=$w-(mb_strlen($s)-mb_strlen($kkm_right)); // кол-во пробелов
        $s=str_replace($kkm_right, str_repeat(" ", max(0, $space_n)), $s); // заменяем тэг сдвига на пробелы
        
        // Заменяем #kkm_center# на пробелы
        $kkm_center="#kkm_center#"; // тэг сдвига в центр
        $space_n=floor(($w-(mb_strlen($s)-mb_strlen($kkm_center)))/2); // кол-во пробелов
        $s=str_replace($kkm_center, str_repeat(" ", max(0, $space_n)), $s); // заменяем тэг сдвига на пробелы
        return $s;
    }

    function get_paper_width() {
    	return $this->config['PaperWidth'];
    }

	// Что нужно выполнить
	function wtf($s) {
		$s=trim($s);
        $p=explode(';', $s);
        $n=count($p);
        if($p[$n-1]=='') {
            unset($p[$n-1]);
            $n-=1;
        }
		if($p[0]=='p') { // Печать строки
			$this->p($p[1]);
		}
		elseif($p[0]=='pm') {
			if($p[1]>0) {
				$w=$p[1];
			}
			else {
				$w=$this->config['PaperWidth'];
			}
			$this->p($p[2], $w);
		}
		elseif($p[0]=='print_bold') { // Печать жирным
			$this->print_bold($p[1]);
		}
		elseif($p[0]=='print_font') { // Печать заданным шрифтом
			$this->print_font($p[1], $p[2]);
		}
		elseif($p[0]=='feed') { // Протяжка
			$this->printer->feed($p[1]);
		}
		elseif($p[0]=='beep') { // Гудок, наверное
			$this->printer->beep($p[1]);
		}
		elseif($p[0]=='qr') { // QR-код
			$this->printer->qrCode($p[1], Printer::QR_ECLEVEL_L, (int) $p[2]);
		}
		elseif($p[0]=='barcode') { // штрих-код
			$this->printer->setBarcodeTextPosition(Printer::BARCODE_TEXT_BELOW);
			$this->printer->setJustification(Printer::JUSTIFY_CENTER);
			if(strlen($p[1])==13 && is_numeric($p[1]))
				$this->printer->barcode($p[1], Printer::BARCODE_JAN13);
			elseif(strlen($p[1])==8 && is_numeric($p[1]))
				$this->printer->barcode($p[1], Printer::BARCODE_JAN8);
			
			$this->printer->setJustification(Printer::JUSTIFY_LEFT);

		}
		elseif($p[0]=='cut_check') { // Отрезка
			$this->printer->cut();
		}
		elseif($p[0]=='b') { // Открытие чека
			$this->b($p[1], $p[2], $p[3]);
		}
		elseif($p[0]=='smde') { // Добавление товара в чек
			// smde;НАЗВАНИЕ_ТОВАРА;ЦЕНА;КОЛВО;НАЛОГ;СЕКЦИЯ;ПСР;ППР;
			$this->smde($p[1], $p[2], $p[3], $p[4], $p[5], $p[6], $p[7]);
		}
		elseif($p[0]=='tmde') { // Оплата чека
			#tmde;СУММА;НОМЕР_ОПЛАТЫ;
        	#tmde;СУММА1;СУММА2;СУММА3;СУММА4;НОМЕР_НАЛОГА_1;НОМЕР_НАЛОГА_2;НОМЕР_НАЛОГА_3;НОМЕР_НАЛОГА_4;
			if($n==3) {
				$this->tmde_ffd_105(array($p[2]=>$p[1]), array($p[2]=>0)); // ффд 1.05
			}
			elseif($n==9) {
				$this->tmde_ffd_105(array($p[1], $p[2], $p[3], $p[4]), array($p[5], $p[6], $p[7], $p[8])); // ффд 1.05
			}
			elseif($n==7) {
				$this->tmde_ffd_11(array($p[1], $p[2], $p[3], $p[4], $p[5]), $p[6]); // ФФД 1.1
			}
			else {
				$error_txt='Неверный формат переданных данных';
				$this->f3->get('logs_model')->save_log($error_txt.' (Касса)', 'error');
				if($this->f3->get('fr_error_ignore')) {
                  return array(
                    'success'=>false,
                    'error'=>$error_txt
                  );
              	}
				echo '<p class="false">'.$error_txt.'</p>';
				exit();
			}
		}
	}

	// Печать строки
	function p($strs, $w=0) {
		$txts=explode('#kkm_br#', $strs);
		foreach ($txts as $t) {
			if(mb_substr($t, 0, mb_strlen('#kkm_bold#'))=='#kkm_bold#') {
               	$this->print_bold($t);
           	}
           	else {
               	$t=$this->text_format($t, $this->config['PaperWidth']);
               	if(!$t) continue;
               	if($w>0) {
               		$str=mb_str_split($t, $w);
               	}
               	else {
               		$str=array($t);
               	}
               	foreach($str as $t) {
               		if(!$t) $t=' ';
               		$this->printer->text($t."\n");
               	}
           	}
		}
	}

	// Печать жирной строки
	function print_bold($text) {
		if($this->config['WideFont']>0) {
			$wfont=2;
		}
		else {
			$wfont=1;
		}
		if($this->config['TallFont']>0) {
			$tfont=2;
		}
		else {
			$tfont=1;
		}
		$this->printer->setTextSize($wfont, $tfont);
		$strs=explode('#kkm_br#', $text);
        foreach ($strs as $s) {
            $s=$this->text_format($s, floor($this->config['PaperWidth']/$wfont));
            $this->printer->text($s."\n");
        }
		$this->printer->setTextSize(1, 1);
	}

	// Печать строки заданным шрифтом
	function print_font($font, $text) {
		if($this->config['WideFont']>0) {
			$wfont=$font;
		}
		else {
			$wfont=1;
		}
		if($this->config['TallFont']>0) {
			$tfont=$font;
		}
		else {
			$tfont=1;
		}
		$this->printer->setTextSize($wfont, $tfont);
		$strs=explode('#kkm_br#', $text);
        foreach ($strs as $s) {
            $s=$this->text_format($s, floor($this->config['PaperWidth']/$wfont));
            $this->printer->text($s."\n");
        }
		$this->printer->setTextSize(1, 1);
	}

	// Открытие чека
	function b($type, $cashier, $print) {
		$this->check_sum=0;
		$type_text = array(1=>"ПРИХОД", 2=>"ВОЗВРАТ ПРИХОДА", 128=>"КОРРЕКЦИЯ/ПРИХОД", 130=>"КОРРЕКЦИЯ/ВОЗВРАТ");
		$this->printer->setJustification(Printer::JUSTIFY_CENTER);
		$this->print_bold($type_text[$type]);
		$this->printer->setJustification(Printer::JUSTIFY_LEFT);
		$cashier=explode('{{user_inn}}', $cashier);
		$this->printer->text('Кассир: '.$cashier[0]."\n");
        if($cashier[1] && mb_strlen($cashier[1])==12) {
            $this->printer->text('ИНН кассира: '.$cashier[1]."\n");
		}
	}

	// Добавление товара в чек
	function smde($title, $price, $qty, $vt, $section, $psr=null, $ppr=null) {
		$price = round($price/100, 2);
        $qty = round($qty/1000, 3);
		$summ = round($price*$qty, 2);
        $this->check_sum += $summ;
		$this->printer->text($title."\n");
		$this->printer->setJustification(Printer::JUSTIFY_RIGHT);
		$this->printer->text(number_format($qty, 3, '.', '').' x '.number_format($price, 2, '.', '')."\n");
		$this->printer->setJustification(Printer::JUSTIFY_LEFT);
		$str=$this->text_format($section."#kkm_right#≡".number_format($summ, 2, '.', ''), $this->config['PaperWidth']);
		$this->printer->text($str."\n");
	}

	// Оплаты ФФД 1.05
	function tmde_ffd_105($pays, $taxes) {
		$this->print_bold("ИТОГ#kkm_right#≡".number_format($this->check_sum, 2, '.', ''));
		$pays_methods=array('Наличными', 'Электронно', 'Картой VISA', 'Картой MasterCard');
		foreach ($pays as $key => $value) {
			if($value>0) {
				$value=round($value/100, 2);
				$str=$this->text_format($pays_methods[$key].'#kkm_right#≡'.number_format($value, 2, '.', ''), $this->config['PaperWidth']);
				$this->printer->text($str."\n");
				if($key==0 && $value>$this->check_sum) {
					$str=$this->text_format('Сдача#kkm_right#≡'.number_format($value-$this->check_sum, 2, '.', ''), $this->config['PaperWidth']);
					$this->printer->text($str."\n");
				}
			}
		}
	}

	// Оплаты ФФД 1.1
	function tmde_ffd_11($pays, $sno) {
		$this->print_bold("ИТОГ#kkm_right#≡".number_format($this->check_sum, 2, '.', ''));
		$pays_methods=array('Наличными', 'Электронно', 'Предоплата', 'Постоплата', 'Встречное предложение');
		foreach ($pays as $key => $value) {
			if($value>0) {
				$value=round($value/100, 2);
				$str=$this->text_format($pays_methods[$key].'#kkm_right#≡'.number_format($value, 2, '.', ''), $this->config['PaperWidth']);
				$this->printer->text($str."\n");
				if($key==0 && $value>$this->check_sum) {
					$str=$this->text_format('Сдача#kkm_right#≡'.number_format($value-$this->check_sum, 2, '.', ''), $this->config['PaperWidth']);
					$this->printer->text($str."\n");
				}
			}
		}
	}

	function check_fnstatus() {
        return array(
            'success'=>true,
            'kkm'=>'Я пользуюсь ЧПМ',
            'ffd'=>'',
            'inn'=>'',
            'kpp'=>'',
            'org_name'=>'',
            'org_address'=>'',
            'ofd_n'=>0,
            'fn_end'=>0
        );
    }

	// Отправка запроса
	function send_ajax($data, $timeout=295, $view=false) {
		if(!$this->f3->get('COOKIE.'.$this->sets['printer'].'_drivers_init')) {
			$this->kkm_init();
		}
		$strs=explode("\n", $data);

		$connector = $this->printer_connect();
		if($this->config['PortType']!='windowsusb' && !$connector->fp) {
        		$error_txt='Невозможно установить соединение';
				$this->f3->get('logs_model')->save_log($error_txt.' (Касса)', 'error');
				if($this->f3->get('fr_error_ignore')) {
                  return array(
                    'success'=>false,
                    'error'=>$error_txt
                  );
              	}
				echo '<p class="false">'.$error_txt.'</p>';
				exit();
        	}

        $profile=null;
        if(isset($this->config['capability']) && !empty($this->config['capability'])) {
        	$profile=CapabilityProfile::load($this->config['capability']);
		}

		$this->printer = new Printer($connector, $profile);
		if(isset($this->config['codepage'])) {
			$this->printer->selectCharacterTable($this->config['codepage']);
		}
		foreach ($strs as $s) {
			$this->wtf($s);
		}
		$this->printer -> close();
		if($view) {
			echo "Запросы отправлены";
		}
		else {
			return array(
				'success'=>true
			);
		}
	}

	function change_status() {
		return 'opened';
	}
}
