<?php

class Cdek {

	private $version = "1.0";
	private $url;
	private $login;
	private $password;
	private $myCity; // город отправителя
	private $clientCity; // город получателя
	private $tariff_id; // id тарифа
	private $delivery_id; //id способа доставки (склад-склад, склад-дверь)
	public $goodsList; //массив мест отправления
	public $tariffList; //массив id тарифов
	private $result;
	private $error;
	public $dateExecute; //планируемая дата заказа
	public $options;
	private $pointsDb;

	public function __construct() {
		$this->dateExecute = date('Y-m-d');
		$this->url = 'http://api.cdek.ru/calculator/calculate_price_by_json.php';
		$this->pointsDb = 'db/cdekPoints.db';
	}

	public function includeOptions() {
		try {
			$db = new PDO('sqlite:db/setting.db');
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$options = $db->prepare("SELECT * FROM `settings`");
			$options->execute();
			$results = $options->fetch(PDO::FETCH_ASSOC);
			$this->options = $results;
			return $this->options;
		} catch ( PDOException $e ) {
			echo "error: " . $e->getMessage() . "<br><br>" . $e->getLine() . "');";
			exit;
		}
	}

	public function getPointsFromDb($city = NULL) {
		$time_sec = time();
		if ( file_exists ( $this->pointsDb ) ) {
			$time_file = filemtime( $this->pointsDb );
			$time = $time_sec-$time_file;
		}
		if ( !file_exists ( $this->pointsDb ) || $time >= 86400 || filesize($this->pointsDb) <= 3000 ) {
			$db = NULL;
			if ( file_exists ( $this->pointsDb ) ) unlink($this->pointsDb);
			$this->checkExistsPointsDb();
			$this->savePoints();
		}
		$where = $this->checkCountry($city);
		try {
			$db = new PDO('sqlite:' . $this->pointsDb);
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$pvz = $db->prepare("SELECT * FROM `points`" . $where['where'] . " ORDER BY `City` ASC");
			unset($where['where']);
			$pvz->execute($where);
			$results = $pvz->fetchAll(PDO::FETCH_ASSOC);
			return $results;
		} catch ( PDOException $e ) {
			echo "error: " . $e->getMessage() . "<br><br>" . $e->getLine() . "');";
			exit;
		}
	}

	public function getCountPoints () {
		$where = $this->checkCountry();
		try {
			$db = new PDO('sqlite:' . $this->pointsDb);
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$pvz = $db->prepare("SELECT COUNT(*), COUNT(DISTINCT city) FROM points" . $where['where']);
			unset($where['where']);
			$pvz->execute($where);
			$results = $pvz->fetch();
			return $results;
		} catch ( PDOException $e ) {
			echo "error: " . $e->getMessage() . "<br><br>" . $e->getLine() . "');";
			exit;
		}
	}

	public function getCityPoints () {
		$where = $this->checkCountry();
		try {
			$db = new PDO('sqlite:' . $this->pointsDb);
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$pvz = $db->prepare("SELECT DISTINCT city, country FROM points" . $where['where'] . " ORDER BY city ASC");
			unset($where['where']);
			$pvz->execute($where);
			$results = $pvz->fetchAll();
			return $results;
		} catch ( PDOException $e ) {
			echo "error: " . $e->getMessage() . "<br><br>" . $e->getLine() . "');";
			exit;
		}
	}

	public function checkCountry($city = NULL) {
		$where = ' WHERE ';
		$arr = array();
		if ( $city != NULL && $city != 'all' ) {
			$cityWhere = ' AND `City`=:city ';
			$arr[':city'] = $city;
		} else {
			$cityWhere = '';
		}
		if ( $this->options['rusDel'] == 1 ) {
			$where .= ' `country`=:rus ' . $cityWhere;
			$arr[':rus'] = "РОССИЯ";
		}
		if ( $this->options['ukrDel'] == 1 ) {
			if ( $where != ' WHERE ' ) $where .= ' OR ';
			$where .= '`country`=:ukr ' . $cityWhere;
			$arr[':ukr'] = "УКРАИНА";
		}
		if ( $this->options['blrDel'] == 1 ) {
			if ( $where != ' WHERE ' ) $where .= ' OR ';
			$where .= '`country`=:blr ' . $cityWhere;
			$arr[':blr'] = "БЕЛОРУССИЯ";
		}
		if ( $this->options['kazDel'] == 1 ) {
			if ( $where != ' WHERE ' ) $where .= ' OR ';
			$where .= '`country`=:kaz ' . $cityWhere;
			$arr[':kaz'] = "КАЗАХСТАН";
		}
		if ( $this->options['armDel'] == 1 ) {
			if ( $where != ' WHERE ' ) $where .= ' OR ';
			$where .= '`country`=:arm ' . $cityWhere;
			$arr[':arm'] = "АРМЕНИЯ";
		}
		if ( $this->options['kgzDel'] == 1 ) {
			if ( $where != ' WHERE ' ) $where .= ' OR ';
			$where .= '`country`=:kzg ' . $cityWhere;
			$arr[':kzg'] = "КИРГИЗИЯ";
		}
		if ( $this->options['zhoDel'] == 1 ) {
			if ( $where != ' WHERE ' ) $where .= ' OR ';
			$where .= '`country`=:zho ' . $cityWhere;
			$arr[':zho'] = "КИТАЙ";
		}
		if ( $where == ' WHERE  AND `City`=:city ' ) $this->calcError("Не выбрано ни одной страны для доставки.");
		$arr['where'] = $where;
		return $arr;
	}

	public function getClientId($id) {
		try {
			$db = new PDO('sqlite:' . $this->pointsDb);
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$pvz = $db->prepare("SELECT * FROM `points` WHERE id=:id");
			$pvz->execute(array(':id' => $id));
			$results = $pvz->fetch(PDO::PARAM_STR);
			return $results;
		} catch ( PDOException $e ) {
			echo "error: " . $e->getMessage() . "<br><br>" . $e->getLine() . "');";
			exit;
		}
	}

	public function getCountryFromCityCode($id) {
		try {
			$db = new PDO('sqlite:db/cdekCity.db');
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$options = $db->prepare("SELECT `country` FROM `city` WHERE `city_id`=:city_id");
			$options->execute(array(':city_id' => $id));
			$results = $options->fetch(PDO::FETCH_ASSOC);
			return $results['country'];
		} catch ( PDOException $e ) {
			echo "error: " . $e->getMessage() . "<br><br>" . $e->getLine() . "');";
			exit;
		}
	}

	public function savePoints() {
		$courier = 'CDEK';
		$pvz = $this->getPoint();
		$query = "INSERT INTO `points` (`PVZCode`, `Address`, `cityCode`, `City`, `WorkTime`, `Phone`, `coordX`, `coordY`, `courier`, `country`) VALUES ";
		$query .= "(:PVZCode, :Address, :cityCode, :City, :WorkTime, :Phone, :coordX, :coordY, :courier, :country)";
		try {
			$db = new PDO("sqlite:" . $this->pointsDb);
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$prepared_query = $db->prepare($query);
			$db->beginTransaction();
			foreach ( $pvz as $get ) {
				$city = mb_strtoupper($get['City'], "UTF-8");
				$country = $this->getCountryFromCityCode($get['CityCode']);
				if ( !mb_stripos( $get['WorkTime'], 'не работает', 0,  'UTF-8' ) && !mb_stripos( $get['Note'], 'не работает', 0,  'UTF-8' ) ) {
					$prepared_query->execute(
						array(
							':PVZCode' => $get['Code'],
							':Address' => $get['Address'],
							':cityCode' => $get['CityCode'],
							':City' => $city,
							':WorkTime' => $get['WorkTime'],
							':Phone' => $get['Phone'],
							':coordX' => $get['coordX'],
							':coordY' => $get['coordY'],
							':courier' => $courier,
							':country' => $country
						)
					);
				}
			}
			$db->commit();
			return $pvz;
		} catch ( PDOException $e ) {
			echo "error: " . $e->getMessage() . "<br><br>" . $e->getLine() . "');";
			exit;
		}
	}

	public function checkExistsPointsDb() {
		try {
			$db = new PDO("sqlite:" . $this->pointsDb);
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$db->exec("CREATE TABLE IF NOT EXISTS `points` (
			`id` INTEGER PRIMARY KEY AUTOINCREMENT,
			`PVZCode` VARCHAR(10),
			`Address` VARCHAR(255),
			`cityCode` INTEGER,
			`City` VARCHAR(50),
			`WorkTime` VARCHAR(100),
			`Phone` VARCHAR(100),
			`coordX` VARCHAR(20),
			`coordY` VARCHAR(20),
			`courier` VARCHAR(20),
			`country` VARCHAR(1)
		);");
		} catch (PDOException $e) {
			$this->calcError('Ошибка в строке ' . $e->getLine() . ': ' . $e->getMessage());
		}
	}

	public function getPoint() {
		$url = "https://integration.cdek.ru/pvzlist.php";
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		$output = curl_exec($ch);
		curl_close($ch);
		$items = simplexml_load_string($output);
		return $items->Pvz;
	}

	public function setDateExecute($date) {
		$this->dateExecute = date($date);
	}

	public function setAuth($login, $password) {
		$this->login = $login;
		$this->password = $password;
	}

	private function _getSecurepassword() {
		return md5 ( $this->dateExecute . '&' . $this->password );
	}

	public function setMyCity($id) {
		$id = (int) $id;
		if ( $id == 0 ) throw new Exception("Неправильно задан город-отправитель.");
		$this->myCity = $id;
	}

	public function setClientCity($id) {
		$id = (int) $id;
		if ( $id == 0 ) throw new Exception("Неправильно задан город-получатель.");
		$this->clientCity = $id;
	}

	public function setTariff_id($id) {
		$id = (int) $id;
		if ( $id == 0 ) throw new Exception("Неправильно задан тариф.");
		$this->tariff_id = $id;
	}

	public function setDeliveryId($id) {
		$id = (int) $id;
		if ( !in_array ( $id, array(1,2,3,4) ) ) throw new Exception("Неправильно задан режим доставки.");
		$this->delivery_id = $id;
	}

	public function addGoodsItemBySize($weight, $length, $width, $height) {
		$weight = (float) $weight;
		if ( $weight == 0.00 ) throw new Exception("Неправильно задан вес места № " . (count($this->getGoodslist())+1) . ".");
		$this->checkParamsItem(array(
			"длина"  => $length,
			"ширина" => $width,
			"высота" => $height
		));
		$this->goodsList[] = array(
			'weight' => $weight,
			'length' => $length,
			'width'  => $width,
			'height' => $height
		);
	}

	public function checkParamsItem($paramsItem) {
		foreach($paramsItem as $k=>$param) {
			$param = (int) $param;
			if ( $param == 0 ) throw new Exception("Неправильно задан параметр '" . $k . "' места № " . (count($this->getGoodslist())+1) . ".");
		}
	}

	public function addGoodsItemByVolume($weight, $volume) {
		$weight = $weight/1000;
		$this->checkParamsItemByVolume(array(
			"вес"          => $weight,
			"объёмный вес" => $volume
		));
		$this->goodsList[] = array(
			'weight' => $weight,
			'volume' => $volume
		);
	}

	public function checkParamsItemByVolume($paramsItem) {
		foreach($paramsItem as $k=>$param) {
			$param = (float) $param;
			if ( $param == 0.00 ) throw new Exception("Неправильно задан параметр '" . $k . "' места № " . (count($this->getGoodslist())+1) . ".");
		}
	}

	public function getGoodslist() {
		if ( !isset ( $this->goodsList ) ) return NULL;
		return $this->goodsList;
	}

	public function addTariffPriority($id, $priority = 0) {
		$id = (int) $id;
		if ( $id == 0 ) throw new Exception("Неправильно задан id тарифа.");
		$priority = ($priority > 0) ? $priority : count($this->tariffList)+1;
		$this->tariffList[] = array(
			'priority' => $priority,
			'id'       => $id
		);
	}

	private function _getTariffList() {
		if ( !isset ( $this->tariffList ) ) return NULL;
		return $this->tariffList;
	}

	private function _getRemoteData($data) {
		$header = array('Content-Type: application/json');
		$data_string = json_encode($data);

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $this->url);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);

		$result = curl_exec($ch);
		curl_close($ch);

		return json_decode($result, true);
	}

	public function calculate() {
		$data = array();
		isset($this->version) ? $data['version'] = $this->version : '';
		$data['dateExecute'] = $this->dateExecute;
		isset($this->login) ? $data['authLogin'] = $this->login : '';
		isset($this->password) ? $data['secure'] = $this->_getSecurepassword() : '';
		isset($this->myCity) ? $data['senderCityId'] = $this->myCity : '';
		isset($this->clientCity) ? $data['receiverCityId'] = $this->clientCity : '';
		isset($this->tariff_id) ? $data['tariffId'] = $this->tariff_id : '';
		( isset($this->tariffList)  ) ? $data['tariffList'] = $this->tariffList : '';
		isset($this->delivery_id) ? $data['modeId'] = $this->delivery_id : '';
//print_r($this->goodsList); exit;
		//список мест
		if( isset($this->goodsList) ) {
			foreach ($this->goodsList as $idGoods => $goods) {
				$data['goods'][$idGoods] = array();
				(isset($goods['weight']) && $goods['weight'] <> '' && $goods['weight'] > 0.00) ? $data['goods'][$idGoods]['weight'] = $goods['weight'] : '';
				(isset($goods['length']) && $goods['length'] <> '' && $goods['length'] > 0) ? $data['goods'][$idGoods]['length'] = $goods['length'] : '';
				(isset($goods['width']) && $goods['width'] <> '' && $goods['width'] > 0) ? $data['goods'][$idGoods]['width'] = $goods['width'] : '';
				(isset($goods['height']) && $goods['height'] <> '' && $goods['height'] > 0) ? $data['goods'][$idGoods]['height'] = $goods['height'] : '';
				(isset($goods['volume']) && $goods['volume'] <> '' && $goods['volume'] > 0.00) ? $data['goods'][$idGoods]['volume'] = $goods['volume'] : '';

			}
		}

		$response = $this->_getRemoteData($data);

		if( isset( $response['result'] ) && !empty( $response['result'] ) ) {
			$this->result = $response;
			return true;
		} else {
			$this->error = $response;
			return false;
		}
	}

	public function engToRus($string) {
		$converter = array(
			'Q' => 'Й', 'W' => 'Ц', 'E' => 'У',
			'R' => 'К', 'T' => 'Е', 'U' => 'Г',
			'O' => 'Щ', 'P' => 'З', '[' => 'Х',
			']' => 'Ъ', 'A' => 'Ф', 'S' => 'Ы',
			'D' => 'В', 'F' => 'А', 'G' => 'П',
			'H' => 'Р', 'J' => 'О', 'K' => 'Л',
			'L' => 'Д', ';' => 'Ж', '\'' => 'Э',
			'Z' => 'Я', 'X' => 'Ч', 'C' => 'С',
			'V' => 'М', 'B' => 'И', 'N' => 'Т',
			'M' => 'Ь', ',' => 'Б', '.' => 'Ю',
			'`' => 'E', 'Y' => 'Н',
		);
		return strtr($string, $converter);
	}

	public function getCity($q) {
		try {
			$db = new PDO('sqlite:db/cdekCity.db');
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			$options = $db->prepare("SELECT * FROM `city` WHERE `city` LIKE '".$q."%' LIMIT 0, 20");
			$options->execute();
			$results = $options->fetchAll(PDO::FETCH_ASSOC);
			return $results;
		} catch ( PDOException $e ) {
			echo "error: " . $e->getMessage() . "<br><br>" . $e->getLine() . "');";
			exit;
		}
	}

	public function response($status, $msg) {
		$response = array(
			'status' => $status,
			'msg' => $msg
		);
		exit(json_encode($response));
	}

	public function calcError($msg) {
		echo "if ( $('#cdek_error').length == 0 ) ";
		echo "$('#delivery-cdek').after('<p id=\"cdek_error\">$msg</p>'); ";
		echo "else ";
		echo "$('#cdek_error').html('<p id=\"cdek_error\">$msg</p>');";
		echo "$('#cdek_error2').html('$msg');";
		exit;
	}

	public function getResult() {
		return $this->result;
	}

	public function declination($n, $form1, $form2, $form5) {
		$n = abs($n) % 100;
		$n1 = $n % 10;
		if ($n > 10 && $n < 20) return $form5;
		if ($n1 > 1 && $n1 < 5) return $form2;
		if ($n1 == 1) return $form1;
		return $form5;
	}

	public function calcResponse ($price, $min, $max, $radioId, $res, $minDate, $maxDate) {
		$del = ' Планируемая дата доставки: <b>';
		if ( $min == $max ) $del .= $minDate . '</b>'; else $del .= "$minDate - $maxDate</b>";
		if ( $this->options['deliveryDate'] == 0 ) $del = '';
		if ( isset($res['id']) ) {
			switch ($this->options['typeCurrency']) {
				case('RUB'): $cur = '&#8381;'; break;
				case('R01235'): $cur = '$'; break;
				case('R01239'): $cur = '€'; break;
				case('R01335'): $cur = '&#8376;'; break;
				case('R01035'): $cur = '&#163;'; break;
				case('R01375'): $cur = '&#20803;'; break;
				case('R01090'): $cur = 'Br'; break;
				case('R01720'): $cur = '&#8372;'; break;
				case('R01060'): $cur = '&#1423;'; break;
				case('R01370'): $cur = 'KGS'; break;
			}
			echo "$('#price-delivery-" . $res['id'] . "').html('<b>" . $price . "</b> " . $cur . "');";
			echo "$('#price_delivery_" . $res['id'] . "').attr('onclick','insertPrice(" . $price . ", \"".$res['City'].", ".addslashes(addslashes($res['Address']))." (Код ПВЗ: " . $res['PVZCode'] . ")\", \"".$res['courier']."\", \"".$del."\"); return false');";
			echo "$('.button').removeAttr('disabled');ajaxflag=0;";
			if ( $this->options['deliveryDate'] == 1 ) {
				echo "$('#delper-" . $res['id'] . "').html('$del');";
			}
			exit();
		}
		echo "if ( $('input[name=\"custom_delivery_tax\"]').length == 0 ) $('#checkout-form').append('<input id=\"custom_delivery_tax\" type=\"hidden\" name=\"custom_delivery_tax\" value>');";
		if ( $this->options['deliveryDate'] > 0 ) {
			echo "if ( $('#delivery-date').length == 0 ) ";
			echo "$('#delivery-cdek').after('<p id=\"delivery-date\">$del</p>'); ";
			echo "else ";
			echo "$('#delivery-date').html('$del'); ";
			if ( is_numeric($this->options['orderFieldDate']) && $this->options['orderFieldDate'] > 0 ) {
				if ( $min == $max ) $del = $minDate; else $del = "$minDate - $maxDate";
				echo "$('#order-fld-{$this->options['orderFieldDate']}').attr('value', '$del');";
			}
		}
		echo "$('input[name=\"custom_delivery_tax\"]').val($price);";
		echo "$('#delivery_id').val($radioId);";
		echo "$('span.osum').html('<img alt=\"\" src=\"//s26.ucoz.net/img/icon/ajsml.gif\" style=\"vertical-align:-4px;\">');";
		echo "$('#checkout-form-mode').val('change');";
		echo "_uPostForm('checkout-form');";
	}

	public function getError() {
		return $this->error;
	}

	public function currencyConverter($cur, $price) {
		$date = date('d/m/Y');
		$path = "http://www.cbr.ru/scripts/XML_dynamic.asp?date_req1=$date&date_req2=$date&VAL_NM_RQ=$cur";
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL,$path);
		curl_setopt($ch, CURLOPT_FAILONERROR,1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 15);
		$r = curl_exec($ch);
		curl_close($ch);
		if ( !empty($r) ) {
			$result = json_decode(json_encode(simplexml_load_string($r)), true);
			if (strpos($result['Record']['Value'], ',')) $result['Record']['Value'] = str_replace(',', '.', $result['Record']['Value']);
			if (strpos($result['Record']['Nominal'], ',')) $result['Record']['Nominal'] = str_replace(',', '.', $result['Record']['Nominal']);
			$cost = round($price * $result['Record']['Nominal'] / $result['Record']['Value'], 2);
			return $cost;
		} else {
			$this->calcError("Ошибка в конвертации валют.");
		}
	}

}

?>