<?php
/**
  * @method VIN图片处理专区
  * @author soul
  * @copyright 2016/3/31
  */
class YpwVinImg extends YpwBase
{
	public $OthVinImg = null;
	public $LibHttp = null;
	public $MainOcr = null;
	public function __construct()
	{
		parent::__construct();
		$this->OthVinImg = new OthVinImg();
		$this->LibHttp = new LibHttp();
		$this->MainOcr = new MainOcr();
	}

	/**
	  * @method 从VIN图库中提取指定车架号的型号信息 L、H开始的 最新3张
	  * @param $vin string [必填] 车架号
	  * @author soul
	  * @return
	  */
	public function getImgOcrSma($vin, $timeout = 5, $fast = false)
	{
		$arr = [];
		if(empty(mvc::$cfg['getImgOcrSmaBtime'])) mvc::$cfg['getImgOcrSmaBtime'] = microtime(true);
		$btime = microtime(true);
		$vin = LibFc::FormatNum($vin);
		$isJinkou = !in_array(substr($vin, 0, 1), ['L', 'H'])? true: false;
		$reg = [];
		if($isJinkou)
		{
			$wmi = substr($vin, 0, 3);
			$vinYear = LibFc::VinYear($vin);
			$chk = sprintf(" and reg_wmi like '%%%s%%' and reg_min_year<=%d and (reg_max_year>=%d or reg_max_year = 0) and reg_status = 1", $wmi, $vinYear, $vinYear);
			$res = $this->get('stand_ocrimg_reg', ['*'], $chk);
			if(empty($res['data'])) return LibFc::ReturnData(true, $arr);
			$reg = $res['data'];
			$reg['reg_wmi'] = explode(',', $reg['reg_wmi']);
		}
		if(empty($reg['min_smacount'])) $reg['min_smacount'] = 5;
		$where = sprintf(" and vii_status in (0,-3,-5) and vii_vin = '%s' order by vii_id desc limit 3", $vin);
		$viires = $this->get('stand_vin_imgs', ['vii_id, vii_status, vii_vin, vii_imghost, vii_img, vii_smastatus, vii_imgocr, vii_imgtype'], $where);
		foreach($viires['data'] as $vk=>$viiArr)
		{
			$hasMatchTxt = [];
			$ocrtime = 0;$smatime = 0;
			if(!empty($viiArr['vii_imgocr']))
			{
				$hasMatchTxt[] = $viiArr['vii_imgocr'];
				$tbtime = microtime(true);
				$chkres = $this->OthVinImg->sma($viiArr, $reg, 0, $fast);
				$smatime += ceil((microtime(true) - $tbtime)*1000);
				if(!empty($chkres['data']['sma']['sma_gxb_code_show']))
				{
					$arr = $chkres['data']['sma'];
					unset($arr['oth']);
					$add = $arr;
					
					// 整形字段
					$intfileds = ['sma_length','sma_width','sma_height', 'sma_wheel','sma_axle','sma_weight','sma_passenger'];
					foreach ($intfileds as $ifiled) 
					{
						if(isset($add[$ifiled]))
						{
							$add[$ifiled] = (int) $add[$ifiled];
						}
					}
					$add['sma_etime'] = time();
					$add['sma_time_total'] = ceil((microtime(true) - $btime)*1000);
					$add['sma_time_ocr'] = $ocrtime;
					$add['sma_time_sma'] = $smatime;
					$this->replace('stand_model_any_ocr', $add);
					return LibFc::ReturnData(true, $arr);
				}
			}

			$hastime = $timeout - (microtime(true) - mvc::$cfg['getImgOcrSmaBtime']);
			if($hastime < 0.6) break;
			$tbtime = microtime(true);
			if($hastime > 2) $hastime = 2;//ocr识别最多2秒
			$ores = $this->ocrViiImg($viiArr, ['timeout'=>$hastime, 'min_smacount'=>5]);
			$ocrtime += ceil((microtime(true) - $tbtime)*1000);
			if(!empty($ores['data']['vii_imgocr']))
			{
				$newviiArr = array_merge($viiArr, $ores['data']);
				$tbtime = microtime(true);
				$chkres = $this->OthVinImg->sma($newviiArr, $reg, 0, $fast);
				$smatime += ceil((microtime(true) - $tbtime)*1000);
				if(!empty($chkres['data']['sma']['sma_gxb_code_show']))
				{
					$arr = $chkres['data']['sma'];
					unset($arr['oth']);
					$add = $arr;
					$add['sma_etime'] = time();
					$add['sma_time_total'] = ceil((microtime(true) - $btime)*1000);
					$add['sma_time_ocr'] = $ocrtime;
					$add['sma_time_sma'] = $smatime;
					$this->replace('stand_model_any_ocr', $add);
					mvc::$cfg['getImgOcrSmaBtime'] = 0;
					return LibFc::ReturnData(true, $arr);
				}
			}
			if(!empty($arr['sma_gxb_code_show'])) break;
		}
		return LibFc::ReturnData(true, $arr);
	}


	/**
	  * @method 从VIN图库中提取指定车架号的发动机 功率  排量 乘坐人数
	  * @param $vin string [必填] 车架号
	  * @author soul
	  * @return
	  */
	public function getImgOcrsmaNoGxb($vin, $timeout = 5)
	{
		$arr = [];
		$vin = LibFc::FormatNum($vin);
		$isJinkou = !in_array(substr($vin, 0, 1), ['L', 'H'])? true: false;
		if(!$isJinkou) return LibFc::ReturnData(true, $arr);
		if(empty(mvc::$cfg['getImgOcrsmaNoGxb'])) mvc::$cfg['getImgOcrsmaNoGxb'] = microtime(true);
		$btime = microtime(true);
		$where = sprintf(" and vii_status in (0,-3,-5) and vii_vin = '%s' order by vii_id desc limit 3", $vin);
		$viires = $this->get('stand_vin_imgs', ['vii_id, vii_status, vii_vin, vii_imghost, vii_img, vii_smastatus, vii_imgocr, vii_imgtype'], $where);
		foreach($viires['data'] as $vk=>$viiArr)
		{
			$hasMatchTxt = [];
			$ocrtime = 0;$smatime = 0;
			if(!empty($viiArr['vii_imgocr']))
			{
				$hasMatchTxt[] = $viiArr['vii_imgocr'];
				$tbtime = microtime(true);
				$chkres = $this->OthVinImg->smaNoGxb($vin, $viiArr['vii_imgocr']);
				$smatime += ceil((microtime(true) - $tbtime)*1000);
				if(!empty($chkres['data']['sma_engine']))
				{
					$arr = $chkres['data'];
					$add = $arr;
					if(!empty($add['sma_passenger'])) $add['sma_passenger'] = (int) $add['sma_passenger'];
					$add['sma_etime'] = time();
					$add['sma_time_total'] = ceil((microtime(true) - $btime)*1000);
					$add['sma_time_ocr'] = $ocrtime;
					$add['sma_time_sma'] = $smatime;
					$this->replace('stand_model_any_ocrjk', $add);
					return LibFc::ReturnData(true, $arr);
				}
			}
			
			$hastime = $timeout - (microtime(true) - mvc::$cfg['getImgOcrsmaNoGxb']);
			if($hastime < 0.6) break;
			$tbtime = microtime(true);
			if($hastime > 2) $hastime = 2;//ocr识别最多2秒
			$ores = $this->ocrViiImg($viiArr, ['timeout'=>$hastime, 'min_smacount'=>5]);
			$ocrtime += ceil((microtime(true) - $tbtime)*1000);
			if(!empty($ores['data']['vii_imgocr']))
			{
				$newviiArr = array_merge($viiArr, $ores['data']);
				$tbtime = microtime(true);
				$chkres = $this->OthVinImg->sma($newviiArr, $reg);
				$smatime += ceil((microtime(true) - $tbtime)*1000);
				if(!empty($chkres['data']['sma_engine']))
				{
					$arr = $chkres['data'];
					$add = $arr;
					$add['sma_etime'] = time();
					$add['sma_time_total'] = ceil((microtime(true) - $btime)*1000);
					$add['sma_time_ocr'] = $ocrtime;
					$add['sma_time_sma'] = $smatime;
					$this->replace('stand_model_any_ocrjk', $add);
					mvc::$cfg['getImgOcrsmaNoGxb'] = 0;
					return LibFc::ReturnData(true, $arr);
				}
			}
			if(!empty($arr['sma_engine'])) break;
		}
		return LibFc::ReturnData(true, $arr);
	}



	/**
	  * @method 
	  * @param $viiArr array [必填] ['vii_id'=>'', 'vii_vin'=>'LVZA53P95HC268455', 'vii_status'=>'', 'vii_imghost'=>'', 'vii_img']
	  * @param $cfg array [选填] ['timeout'=>5] timeout:整体超时时间默认5秒 
	  * @author soul
	  * @return
	  */
	public function ocrViiImg($viiArr, $cfg = ['timeout'=>5])
	{
		if(!isset($cfg['timeout'])) $cfg['timeout'] = 5;
		$btime = microtime(true);
		$vin = $viiArr['vii_vin'];
		$vin18 = substr($vin, 0, 8);
		$vin13 = substr($vin, 0, 3);
		$vin1014 = substr($vin, 9, 5);
		$imgurl = mvc::$cfg['urls']['vinimg_'.$viiArr['vii_imghost']].$viiArr['vii_img'];
		if(!isset($viiArr['vii_imgtype'])) return LibFc::ReturnData(false, '缺少图片类型vii_imgtype');
		$image = $this->LibHttp->fetch($imgurl);
		if(!LibFc::isValidImageContent($image) || stripos($image, 'Not Found') || strlen($image) < 128){
			$set = ['vii_status'=>-1];
			$set['vii_smaerr'] = '无效图:图片不存在或过小';
			$this->set('stand_vin_imgs', $set, sprintf(' and vii_id=%d', $viiArr['vii_id']));
			return LibFc::ReturnData(true, $set);
		}
		$set = [];
		$image = base64_encode($image);
		$ocrstatusArr = [0=>2, 90=>4, 180=>8, 270=>16];
		foreach([0,180,90,270] as $rotate){
			//计算剩余时间
			$hastime = $cfg['timeout'] - (microtime(true) - $btime);
			if($hastime < 0.1) break;
			$res = $this->MainOcr->paddleOcr($image, ['rotate'=>$rotate]);
			$ocrtxt = implode("\n", $res['data']);
			//包含前8 或者前3+10~14
			if(stripos($ocrtxt, $vin18) !== false || (stripos($ocrtxt, $vin13) !== false && stripos($ocrtxt, $vin1014) !== false)){
				$set['vii_imgocr'] = $ocrtxt;
				$set['vii_ocrstatus'] = $ocrstatusArr[$rotate];
				break;
			}else if(strlen($ocrtxt) > strlen($set['vii_imgocr'])){//无法匹配，留最长
				$set['vii_imgocr'] = $ocrtxt;
				$set['vii_ocrstatus'] = $ocrstatusArr[$rotate];
			}
		}
		if(!empty($set)){
			$res = $this->get('stand_model_any', ['sma_id'], sprintf(" and sma_vin1_8='%s' limit 1", $vin18), true);
			if(empty($res['data'])){
				foreach(['yt', 'ocr'] as $vtype){
					$tvin = '';
					if($vtype == 'yt'){
						$res = $this->MainOcr->vin($image, ['site'=>'yt', 'nocoll'=>true]);
						$tvin = $res['data'];
					}else{
						$ocrtxt = implode("\n", $res['data']);
						if(preg_match_all('/[0-9A-Z]{14}\d{3}/i', $ocrtxt, $matches)){
							foreach($matches[0] as $tvin){
								$check = LibFc::VinCheckCode($tvin);
								if($check['ok']) break;
							}
						}
					}
					if(strlen($tvin) == 17 && $tvin != $vin){
						$res = $this->get('stand_model_any', ['sma_id'], sprintf(" and sma_vin1_8='%s' limit 1", substr($tvin, 0, 8)), true);
						if(!empty($res['data'])){
							$vin = $tvin;
							$set['vii_vin'] = $vin;
							$set['vii_vin1_3'] = substr($vin, 0, 3);
							$set['vii_vin1_8'] = substr($vin, 0, 8);
							$set['vii_vin10_12'] = substr($vin, 9, 3);
							$set['vii_vin13_17'] = substr($vin, 12, 5);
							$set['vii_year'] = LibFc::VinYear(substr($vin, 9, 1));
							$set['vii_vinocr'] = $vtype;
							break;
						}
					}
				}
			}

			if(strlen($set['vii_imgocr']) > 0){
				//二次处理图片类型
				if(!in_array($viiArr['vii_imgtype'], [1,2])){
					$timgtype = $this->OthVinImg->getImgType($set['vii_imgocr'], $viiArr['vii_vin']);
					//无效图 或者普通图长度小于17的
					if(in_array($timgtype, [-1,0]) && strlen($set['vii_imgocr']) < 20){
						$set['vii_status'] = -1;
						$viiArr['vii_status'] = -1;
						$set['vii_smaerr'] = '无效图:图类型['.$timgtype.'] 长度'.strlen($set['vii_imgocr']);
					}
				}
			}else{
				$set['vii_imgocr'] = '';
			}
			if($viiArr['vii_status'] != 1) $set['vii_smastatus'] = 'sma';
			if(empty($set['vii_ocrstatus'])) $set['vii_ocrstatus'] = 2;
			$set['vii_smatime'] = time();
		}else{
			$set['vii_ocrstatus'] = -2;
		}
		$this->set('stand_vin_imgs', $set, sprintf(' and vii_id=%d', $viiArr['vii_id']));
		return LibFc::ReturnData(true, $set);
	}

	/**
	  * @method  ocr提取制造日期
	  * @param $viiArr array [必填] ['vii_vin'=>'LVZA53P95HC268455', 'vii_imgocr'=>'', 'vii_year'=>'']
	  * @author soul
	  * @return
	  */
	public function ocrVinDate($viiArr)
	{
		$arr = ['okdate'=>'', 'dates'=>[]];
		$regs = [
			'/制造年月[\s\:]*(20\d{2})[\.\-年\/]?(\d{1,2})/iu',
			'/制造年月[\s\:]*(\d{2})[\.\-年\/](\d{1,2})/iu',
			'/生产日期[\s\:]*(20\d{2})[\.\-年\/]?(\d{1,2})/iu',
		];
		$vin = $viiArr['vii_vin'];
		if(empty($viiArr['vii_year'])) $viiArr['vii_year'] = LibFc::VinYear($vin);
		$ocrtxt = strtr($viiArr['vii_imgocr'], ["\r\n"=>"\n", '：'=>':']);
		$ocrDate = '';
		//找已有样本的日期区间
		$arr['dates'] = [];
		$com = sprintf(" and alb_vin1_3='%s' and alb_vin4_8='%s' and alb_vin10_11='%s' and alb_from != 'ocr'", substr($vin, 0, 3), substr($vin, 3, 5), substr($vin, 9, 2));
		$whereArr = [
			[
				$com.sprintf(" and alb_vin12='%s' and alb_vin13_17 < '%s' order by alb_vin13_17 desc limit 1", substr($vin, 11, 1), substr($vin, -5)),
				$com.sprintf(" and alb_vin12='%s' and alb_vin13_17 > '%s' order by alb_vin13_17 asc limit 1", substr($vin, 11, 1), substr($vin, -5)),
			],
			[
				$com.sprintf(" and concat(alb_vin12, alb_vin13_17) < '%s' order by concat(alb_vin12, alb_vin13_17) desc limit 1", substr($vin, -6)),
				$com.sprintf(" and concat(alb_vin12, alb_vin13_17) > '%s' order by concat(alb_vin12, alb_vin13_17) asc limit 1", substr($vin, -6)),
			]
		];
		foreach($whereArr as $tv){
			$res = $this->get('yp_allvin_base', ['alb_date'], $tv[0], true);
			if(!empty($res['data']['alb_date'])) $arr['dates'][] = date('Y-m', strtotime($res['data']['alb_date']));
			$res = $this->get('yp_allvin_base', ['alb_date'], $tv[1], true);
			if(!empty($res['data']['alb_date'])) $arr['dates'][] = date('Y-m', strtotime($res['data']['alb_date']));
			if(!empty($arr['dates'])) break;
		}
		$arr['dates'] = array_unique($arr['dates']);
		sort($arr['dates']);
		foreach($regs as $reg){
			if(preg_match($reg, $ocrtxt, $match)){
				if(strlen($match[1]) == 2) $match[1] = '20'.$match[1];
				$ocrtime = strtotime($match[1].'-'.$match[2].'-01');
				$ocrY = date('Y-m', $ocrtime);
				$ocrDate = date('Y-m', $ocrtime);
				$arr['matches'][] = $ocrDate;
				if($ocrtime < time() && abs($ocrY - $viiArr['vii_year']) < 2){
					foreach($arr['dates'] as $tdate){
						$d1 = DateTime::createFromFormat('Y-m', $ocrDate);
						$d2 = DateTime::createFromFormat('Y-m', $tdate);
						if ($d1 && $d2 && abs(($d1->format('Y') - $d2->format('Y')) * 12 + ($d1->format('m') - $d2->format('m'))) <= 2){
							$arr['okdate'] = $ocrDate;
							return LibFc::ReturnData(true, $arr);
						}
					}
				}
			}
		}
		return LibFc::ReturnData(true, $arr);
	}

	/**
	  * @method  ocr提取EPC代码
	  * @param $viiArr array [必填] ['vii_id'=>'', 'vii_vin'=>'LVZA53P95HC268455', 'vii_imgocr'=>'', 'vii_year'=>'']
	  * @param $epcCodes array [选填] 限定原厂代码
	  * @author soul
	  * @return
	  */
	public function ocrVinEpcCode($viiArr, $epcCodes = [])
	{
		$arr = ['ok'=>'', 'matches'=>[]];
		$vin = $viiArr['vii_vin'];
		$v18 = substr($vin, 0, 8);
		$Ypc67Base = new BaseDb(mvc::$cfg['DB']['YPCAR67']);
		if(empty($epcCodes)){
			$epcCodes = [];
			$table = 'yp_model3 
			JOIN yp_model2 ON m3_m2_id = m2_id 
			JOIN yp_model1 ON m2_m1_id = m1_id
			JOIN yp_vin_model3_link ON vm3_m3_id = m3_id
			JOIN yp_vin ON vin_id = vm3_vin_id
			JOIN yp_model3_etk_code ON mec_m3_id = m3_id';
			$res = $Ypc67Base->get($table, ['mec_code ecode'], sprintf(" and vin_full='%s' AND mec_code LIKE '%%-%%' GROUP BY mec_code", $v18));
			foreach($res['data'] as $v){
				$epcCodes[] = $v['ecode'];
			}

			$table = 'yp_model3 
			JOIN yp_model2 ON m3_m2_id = m2_id 
			JOIN yp_model1 ON m2_m1_id = m1_id
			JOIN yp_vin_model3_link ON vm3_m3_id = m3_id
			JOIN yp_vin ON vin_id = vm3_vin_id
			JOIN yp_model3_modcode ON mem_m3_id = m3_id';
			$res = $Ypc67Base->get($table, ['mem_code ecode'], sprintf(" and vin_full='%s' AND mem_code LIKE '%%-%%' GROUP BY mem_code", $v18));
			foreach($res['data'] as $v){
				$v['ecode'] = explode('@', $v['ecode']);
				if(!in_array($v['ecode'][0], $epcCodes)) $epcCodes[] = $v['ecode'][0];
			}

			$res = $this->get('stand_vin_epccode', ['vie_unicode ecode'], sprintf(" and vie_vin like '%s%%' GROUP BY vie_unicode", $v18));
			foreach($res['data'] as $v){
				if(!in_array($v['ecode'], $epcCodes)) $epcCodes[] = $v['ecode'];
			}
		}
		
		$ocrtxt = strtr($viiArr['vii_imgocr'], ["\r\n"=>"\n", '：'=>':', '一'=>'-', '——'=>'-']);
		if(!empty($epcCodes)){
			$arr['ok'] = '';
			//完整匹配
			foreach($epcCodes as $unicode){
				if(stripos($ocrtxt, $unicode) !== false){
					$arr['ok'] = $unicode;
					break;
				}
			}
		}
		if(!$arr['ok']){
			$regs = [
				'/专用号[: ]?([A-Z][A-Z0-9]{3,}\-[A-Z0-9]{2,})[^A-Z0-9]/i',
				'/[^A-Z0-9]([A-Z][A-Z0-9]{3,}\-[A-Z0-9]{2,})[^A-Z0-9]?/i',
			];
			foreach($regs as $reg){
				if(preg_match_all($reg, $ocrtxt, $matches, PREG_SET_ORDER)){
					foreach($matches as $match){
						$tcode = trim(strtoupper($match[1]));
						$arr['matches'] = $tcode;
						$arr['ok'] = $this->getOkCode($tcode, $epcCodes);
						if($arr['ok']) return LibFc::ReturnData(true, $arr);

						//直接找库
						$res = $this->get('stand_vin_epccode', ['vie_unicode ecode'], sprintf(" and vie_unicode ='%s' limit 1", $tcode), true);
						if(empty($res['data'])){
							$res = $Ypc67Base->get('toyota_app_series', ['ser_col_4 ecode'], sprintf(" and ser_col_4='%s' limit 1", $tcode), true);
						}
						if(!empty($res['data'])){
							$arr['ok'] = $tcode;
							return LibFc::ReturnData(true, $arr);
						}

						//找相似的
						$res = $this->get('stand_vin_epccode', ['distinct vie_unicode'], sprintf(" and vie_unicode like '%s%%' and length(vie_unicode)=%d", substr($tcode, 0, 2), strlen($tcode)));
						if($res['data']){
							$tcodes = array_column($res['data'], 'vie_unicode');
							$arr['ok'] = $this->getOkCode($tcode, $tcodes);
							if($arr['ok']) return LibFc::ReturnData(true, $arr);
						}

						$res = $Ypc67Base->get('toyota_app_series', ['distinct ser_col_4'], sprintf(" and ser_col_4 like '%s%%' and length(ser_col_4)=%d", substr($tcode, 0, 2), strlen($tcode)));
						if($res['data']){
							$tcodes = array_column($res['data'], 'ser_col_4');
							$arr['ok'] = $this->getOkCode($tcode, $tcodes);
							if($arr['ok']) return LibFc::ReturnData(true, $arr);
						}
					}
				}
			}
		}
		return LibFc::ReturnData(true, $arr);
	}


	private function getOkCode($tcode, $epcCodes){
		$okcode = '';
		foreach($epcCodes as $unicode){
			if(strlen($unicode) == strlen($tcode)){
				$diffs = LibFc::diffByPos($unicode, $tcode);
				$diffCount = count($diffs);
				if($diffCount <= 2){
					foreach($diffs as $div){
						sort($div);
						$chars = implode('', $div);
						if(in_array($chars, ['0O','0o','0C','1I','1l','CG', 'CO', '6G'])){
							$diffCount--;
						}
					}
					if($diffCount == 0){
						return $unicode;
					}
				}
			}
		}
		return $okcode;
	}

	public function reocrByUrl($imgurl)
	{
		$ocrtxt = '';
		$MainOcr = new MainOcr();
		$LibHttp = new LibHttp();
		$image = $LibHttp->fetch($imgurl);
		$image = base64_encode($image);
		if(strlen($image) > 1024){
			$res = $MainOcr->paddleOcr($image);
			$ocrtxt = implode("\n", $res['data']);
		}
		return LibFc::ReturnData(true, $ocrtxt);
	}
}