<?php
ini_set('serialize_precision', 14);
ini_set('precision', 14);
require_once (__DIR__.'/../php/conversion.php');
require_once(__DIR__.'/../php/product.php');
require_once(__DIR__.'/../php/retail.php');
require_once(__DIR__.'/../php/inventory.php');
class Recipe {

	public function __construct() {
		$this->dataPath = '../Recipes/recipes-bodi.json';
		$this->categroyCssPath = '../setting/admin.json';
		$this->inventory = new InventoryCore();
		$this->retail = new Retail();
		$this->img_dir = '../images/Recipe/';
	}

	public function loadData() {
		if (!is_file($this->dataPath)) {
			return null;
		}

		return json_decode(file_get_contents($this->dataPath), true);
	}

	public function loadCategoryCssData() {
		if (!is_file($this->categroyCssPath)) {
			return null;
		}

		return json_decode(file_get_contents($this->categroyCssPath), true);
	}
	public function loadAllData($options) {
		$data = array();
		$res = array();
		$Invflag = $options['Invflag'];
		if($Invflag == 1) {
			$inventoryFiles = $this->inventory->getList();
	        $rs = array_map(function($filename){
	            return array(
	                'format' => $this->inventory->removeExt($filename),
	                'data' => $this->inventory->loadInventory($filename),
	            );
	        }, $inventoryFiles);

	    	$res['inventories'] = array_values($rs);
		}
		//$data['inventory'] = $this->loadAllInventory();
		$res['recipes'] = $this->loadData();
		$res['formats'] = array();
		for ($i = 0; $i < sizeof($res['recipes']); $i++) {
			$res['recipes'][$i]['index'] = $i;
			if (array_search($res['recipes'][$i]['RecipeFormat'], $res['formats']) === false) {
				$res['formats'][] = $res['recipes'][$i]['RecipeFormat'];
			}

			$res['recipes'][$i] = $this->setCategoryColor($res['recipes'][$i]);
		}

        $res['supplierLog'] = $this->inventory->loadJson(__DIR__.'/../Supplier/supplier-log.json');
        $res['setting'] = $this->inventory->loadJson(__DIR__.'/../setting/admin.json');
		
		return $res;
	}

	public function setCategoryColor($data)
	{
		$categoryCss = $this->loadCategoryCssData() ?? [];
		$categoryCss = $categoryCss['CategoryCss'];

		foreach ($data['Steps'] as $indexStep => $step) {
			foreach ($categoryCss as $category) {
				if (isset($step['Format']) && $step['Format'] == $category['category']) {
					$data['Steps'][$indexStep]['Format_color'] = $category['style']['background-color'];
				}
			}
		}

		return $data;
	}


    public function loadAllInventoryFiles() {
        $inventoryFiles = $this->inventory->getList();
        $rs = array_map(function($filename){
            return array(
                'format' => $this->inventory->removeExt($filename),
                'data' => $this->inventory->loadInventory($filename),
            );
        }, $inventoryFiles);
        return array_values($rs);
    }
    private function getInventoryFormats($inventories) {
    	return array_map(function($inventory) {
    		return $inventory['format'];
    	}, $inventories);
    }
	public function loadAllInventory() {
		$data = array();
		$inventories = $this->loadAllInventoryFiles();
		$this->inventoryDataPaths = $this->getInventoryFormats($inventories);
		foreach ($inventories as $inventory) {
			if (is_array($inventory['data']))
				foreach ($inventory['data'] as $key => $item) {
					$item['index'] = $key;
					$item['category'] = $inventory['format'];
					$data[] = $item;
				}
		}

		return $data;
	}

	public function loadRecipe($recipeName, $moneyRates) {
		$result = array();
		$data['recipes'] = $this->loadData();

		for ($i = 0; $i < sizeof($data['recipes']); $i++) {
			if ($data['recipes'][$i]['RecipeName'] == $recipeName) {
				$result = &$data['recipes'][$i];
				break;
			}
		}

		$result['RecipeCost'] = $this->calculateRecipeCost($result, $result['Serving'], $moneyRates);
		$result['RecipeCost'] = floatval($result['RecipeCost'] . '');



		$success = true;
		if (!file_put_contents($this->dataPath . '_temp', json_encode($data['recipes'], JSON_PRETTY_PRINT))) {
			$success = false;
		}


		if ($success) {
			$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
		} else {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		}

		return $result;
	}
	public function dupRecipe($index, $recipeName, $recipeFormat) {
		$result = array();
		$result['success'] = false;
		if (!$recipeName || !$recipeFormat || $index < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}
		$data = $this->loadData();
		if (!isset($data[$index])) {
			$result['error'] = "index {$index} does not exist";
		} else {
			$recipe = $data[$index];
			$recipe['RecipeName'] = $recipeName;
			$recipe['RecipeFormat'] = $recipeFormat;
			$data[] = $recipe;
			$this->inventory->saveJson($this->dataPath, $data);
			$result['success'] = true;
		}
		return $result;
	}
	public function update($dataElement, $index) {
		$result = array();
		$result['success'] = false;
		if (!$dataElement || empty($dataElement) || $index < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = [];
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			if (!isset($dataElement)) {
				$result['success'] = false;
				$result['error'] = 'No data to update';
				return $result;
			}

			$data[$index] = $dataElement;

			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}


			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['success'] = true;
			$result['recipe'] = $dataElement;
			return $result;
		}

		return $result;
	}
	public function createNewInstruction($data = null) {
		$object = array();
		$object['Step'] = 0;
		$object['Instruction'] = '';
		if ($data) {
			$object = array_replace($object, array_intersect_key($data, $object));
		}
		return $object;
	}
	public function createNewSubTotal($data = null) {
		$object = array();
		$object['Step'] = 0;
		$object['SubTotal'] = '';
		if ($data) {
			$object = array_replace($object, array_intersect_key($data, $object));
		}
		return $object;
	}
	public function addInstruction($instruction) {
		$step = $instruction['Step'];
		$index = $instruction['Index'];
		$result = array();
		$result['success'] = true;
		if (!$step || !$index < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = $this->loadData();

		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			$recipe = &$data[$index];
			$inst = $this->createNewInstruction($instruction);
			if (!isset($recipe['Steps'])) {
				$recipe['Steps'] = array();
			}
			if (count($recipe['Steps']) <= 0 || count($recipe['Steps']) <= $step - 1) {
				$recipe['Steps'][] = $inst;
			} else {
				array_splice($recipe['Steps'], $step-1, 0, array($inst));
				$this->reindex($recipe['Steps']);
			}
			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}
			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);
			return $result;
		}
		return $result;
	}
	public function addSubTotal($subtotal) {
		$step = $subtotal['Step'];
		$index = $subtotal['Index'];
		$result = array();
		$result['success'] = true;
		if (!$step || !$index < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = $this->loadData();

		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			$recipe = &$data[$index];
			$newsub = $this->createNewSubTotal($subtotal);
			if (!isset($recipe['Steps'])) {
				$recipe['Steps'] = array();
			}
			if (count($recipe['Steps']) <= 0 || count($recipe['Steps']) <= $step - 1) {
				$recipe['Steps'][] = $newsub;
			} else {
				array_splice($recipe['Steps'], $step-1, 0, array($newsub));
				$this->reindex($recipe['Steps']);
			}
			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}
			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);
			return $result;
		}
		return $result;
	}
	public function addDiagram() {
		$step = (int)$_POST['step'];
		$index = (int)$_POST['index'];
		$result = array();
		$result['success'] = true;
		if (!$step || empty($step) || $index < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			$recipe = &$data[$index];
			$diagram = [
				'Step'=> $step,
				'diagram' => '',
				'image' => ''
			];
			if (!isset($recipe['Steps'])) {
				$recipe['Steps'] = array();
			}
			if (count($recipe['Steps']) <= 0 || count($recipe['Steps']) <= $step - 1) {
				$recipe['Steps'][] = $diagram;
			} else {
				array_splice($recipe['Steps'], $step-1, 0, array($diagram));
				$this->reindex($recipe['Steps']);
			}
			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}
			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);
			return $result;
		}

		return $result;
	}
	public function updateInstruction($data) {
		$instruction = json_decode($data['data'], true);
		$recipeIndex = $instruction['recipeIndex'];
		$stepIndex = $instruction['stepIndex'];
		$delete = $instruction['delete'];
		$result = array();
		$result['success'] = true;
		$data = $this->loadData();

		if (!isset($data[$recipeIndex])) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
		} else {
			$recipe = &$data[$recipeIndex];
			if (isset($recipe['Steps'][$stepIndex])) {
				$inst = $recipe['Steps'][$stepIndex];
				$inst = array_replace($inst, array_intersect_key($instruction['instruction'], $inst));
				if ($delete) {
					array_splice($recipe['Steps'], $stepIndex, 1);
					$this->reindex($recipe['Steps']);
				} else {
					if (isset($_FILES['image'])) {
						$allowedExts = array("gif", "jpeg", "jpg", "png");
						$extension = strtolower(pathinfo($_FILES['image']['name'],PATHINFO_EXTENSION));
						if (in_array($extension, $allowedExts)) {
							$filename = md5(time()).'.'.$extension;
							move_uploaded_file($_FILES['image']["tmp_name"], $this->img_dir . $filename);
							if (!empty($inst['image']) && file_exists($this->img_dir.$inst['image'])) {
								unlink($this->img_dir.$inst['image']);
							}
							$inst['image'] = $filename;
						}
					}
					$recipe['Steps'][$stepIndex] = $inst;
				}
			}
			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}
			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['Index'] = $recipeIndex;
			$result['Item'] = $this->setCategoryColor($recipe);
		}
		return $result;
	}
	public function updateDiagram($data) {
		$data = json_decode($data['data'], true);
		$recipeIndex = $data['recipeIndex'];
		$stepIndex = $data['stepIndex'];
		$delete = $data['delete'];
		$result = array();
		$result['success'] = true;
		$data = $this->loadData();

		if (!isset($data[$recipeIndex])) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
		} else {
			$recipe = &$data[$recipeIndex];
			if (isset($recipe['Steps'][$stepIndex])) {
				$step = $recipe['Steps'][$stepIndex];
				if ($delete) {
					array_splice($recipe['Steps'], $stepIndex, 1);
					$this->reindex($recipe['Steps']);
				} else {
					if (isset($_FILES['image'])) {
						$allowedExts = array("gif", "jpeg", "jpg", "png");
						$extension = strtolower(pathinfo($_FILES['image']['name'],PATHINFO_EXTENSION));
						if (in_array($extension, $allowedExts)) {
							$filename = md5(time()).'.'.$extension;
							move_uploaded_file($_FILES['image']["tmp_name"], $this->img_dir . $filename);
							if (!empty($step['image']) && file_exists($this->img_dir.$step['image'])) {
								unlink($this->img_dir.$step['image']);
							}
							$step['image'] = $filename;
						}
					}
					$recipe['Steps'][$stepIndex] = $step;
				}
			}
			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}
			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['Index'] = $recipeIndex;
			$result['Item'] = $this->setCategoryColor($recipe);
		}
		return $result;
	}
	private function _updateStep($recipe, $step) {
		foreach ($recipe['Steps'] as $key => &$s) {
			if ($s['Step'] == $step['Step']) {
				if ($step['delete'] == 'true') {
					unset($recipe['Steps'][$key]);
					break;
				}
				switch ($step['type']) {
					case 'subtotal':
						break;
					default:
						$s['StepQuantity'] = $step['StepQuantity'];
						$s['StepMultiplier'] = $step['StepMultiplier'];
						break;
				}
				break;
			}
		}
		$recipe['Steps'] = array_values($recipe['Steps']);
		return $recipe;
	}
	public function updateSubTotal($step) {
		$recipeIndex = $step['recipeIndex'];
		$result = array();
		$result['success'] = true;
		$data = $this->loadData();
		if (!isset($data[$recipeIndex])) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
		} else {
			$recipe = &$data[$recipeIndex];
			foreach ($step['steps'] as $s) {
				$recipe = $this->_updateStep($recipe, $s);
			}
			$this->reindex($recipe['Steps']);
			$recipe['RecipeCost'] = $this->calculateRecipeCost($recipe, $recipe['Serving'], 1);
			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}
			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}
			$result['Index'] = $recipeIndex;
			$result['Item'] = $this->setCategoryColor($recipe);
		}
		return $result;
	}
	public function reindex(&$array) {
		array_walk($array, function (&$e, $key) {
				$e['Step']=(string)($key+1);
		});
	}

	public function addStep($step, $index, $recipeCost) {
		$result = array();
		$result['success'] = false;
		if (!$step || empty($step) || $index < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = [];
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			if (!isset($step)) {
				$result['success'] = false;
				$result['error'] = 'No step to add';
				return $result;
			}

			$recipe = &$data[$index];

			if (!isset($recipe['Steps'])) {
				$recipe['Steps'] = array();
			}

			if (count($recipe['Steps']) <= 0 || count($recipe['Steps']) <= $step['Step'] - 1) {
				$recipe['Steps'][] = $step;
			} else {
				$first = array_slice($recipe['Steps'], 0, $step['Step'] - 1);
				$first[] = $step;
				$last = array_slice($recipe['Steps'], $step['Step'] - 1);
				$recipe['Steps'] = array_merge($first, $last);
			}

			$this->standardlizeSteps($recipe);

			$recipe['RecipeCost'] = floatval($recipeCost);
			$recipe['RecipeDate'] = date('Y-m-d');

			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}


			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['success'] = true;
			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);
			return $result;
		}

		return $result;
	}

	public function updateStep($step, $index, $stepIndex, $recipeCost) {
		$result = array();
		$result['success'] = false;
		if (!$step || empty($step) || $index < 0 || $stepIndex < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = [];
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			if (!isset($step)) {
				$result['success'] = false;
				$result['error'] = 'No step to add';
				return $result;
			}

			$recipe = &$data[$index];

			if (!isset($recipe['Steps'])) {
				$recipe['Steps'] = array();
			}

			if ($stepIndex == $step['Step'] - 1) {
				$recipe['Steps'][$stepIndex] = $step;
			} else {
				array_splice($recipe['Steps'], $stepIndex, 1);
				if (count($recipe['Steps']) <= 0 || count($recipe['Steps']) <= $step['Step'] - 1) {
					$recipe['Steps'][] = $step;
				} else {
					$first = array_slice($recipe['Steps'], 0, $step['Step'] - 1);
					$first[] = $step;
					$last = array_slice($recipe['Steps'], $step['Step'] - 1);
					$recipe['Steps'] = array_merge($first, $last);
				}
			}

			$this->standardlizeSteps($recipe);

			$recipe['RecipeCost'] = floatval($recipeCost);
			$recipe['RecipeDate'] = date('Y-m-d');

			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}


			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['success'] = true;
			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);
			return $result;
		}

		return $result;
	}

	public function updateSteps($steps) {
		$result = array();
		$result['success'] = false;
		$data = [];
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			$index = isset($steps[0]) ? $steps[0]['Index'] : null;
			$recipe = &$data[$index];

			foreach ($steps as $index2 => $step) {
				$stepIndex = $step['StepIndex'];
				$StepMultiplier = $step['Step']['StepMultiplier'];

				if (!isset($recipe['Steps'])) {
					break;
				}
				
				$recipe['Steps'][$index2]['StepMultiplier'] = $StepMultiplier;
			}

			$recipe['Steps'] = array_values($recipe['Steps']);

			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}


			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['success'] = true;
			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);
			return $result;
		}

		return $result;
	}

	public function sequence($recipeIndex) {
		$result = array();
		$result['success'] = false;
		$data = [];
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
            $recipe = &$data[$recipeIndex];
			$categoryCss = $this->loadCategoryCssData() ?? [];
			$categoryCss = $categoryCss['CategoryCss'];
			$categories = [];
			$newSteps = [];

			foreach ($recipe['Steps'] as $step) {
				if (!in_array($step['Format'], $categories)) {
					$categories[] = $step['Format'];
				}
			}

			$newCats = [];
			foreach ($categoryCss as $cat) {
				foreach ($categories as $cat2) {
					if ($cat['category'] === $cat2) {
						$newCats[] = $cat2;
					}
				}
			}

			sort($categories);
			$newCats[] = $categories[0];

			foreach ($newCats as $category) {
				foreach ($recipe['Steps'] as $step) {
					if ($category === $step['Format']) {
						$newSteps[$category][] = $step;
					}
				}
			}

			$sortedSteps = [];
			$counter = 1;
			foreach ($newSteps as $index => $step) {
				usort($newSteps[$index], function ($a, $b) {
					return strcmp($a["Ingredient"], $b["Ingredient"]);
				});

				foreach ($newSteps[$index] as $step) {
					$step['Step'] = $counter;
					$sortedSteps[] = $step;

					$counter++;
				}
			}
			$finalSteps = array_values($sortedSteps);

			$tempArr = [];
			foreach ($finalSteps as &$v) {
				if (!isset($tempArr[$v["Ingredient"]]))
				$tempArr[$v["Ingredient"]] = $v;
			}
			$recipe['Steps'] = array_values($tempArr);
			
			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}


			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['success'] = true;
			$result['Item'] = $this->setCategoryColor($recipe);
			$result['Index'] = $recipeIndex;
        }
		

		return $result;
	}

	public function reorder($reorderData) {
		$result = array();
		$result['success'] = false;
		$index = (int)$reorderData['recipeIndex'];
		$oldStepIndex = (int)$reorderData['oldStepIndex'];
		$newStepIndex = (int)$reorderData['newStepIndex'];
		if ($index < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = [];
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
		} else {
			$recipe = &$data[$index];
			$temp = array($recipe['Steps'][$oldStepIndex]);
			array_splice($recipe['Steps'], $oldStepIndex, 1);
			array_splice($recipe['Steps'], $newStepIndex, 0, $temp);

			$this->standardlizeSteps($recipe);

			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}

			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['success'] = true;
			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);
		}

		return $result;
	}
	public function deleteStep($index, $stepIndex, $recipeCost) {
		$result = array();
		$result['success'] = false;
		if ($index < 0 || $stepIndex < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = [];
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			$recipe = &$data[$index];

			array_splice($recipe['Steps'], $stepIndex, 1);

			$this->standardlizeSteps($recipe);

			$recipe['RecipeCost'] = floatval($recipeCost);

			$success = true;
			if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
				$success = false;
			}


			if ($success) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['success'] = true;
			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);
			return $result;
		}

		return $result;
	}

	public function updateInfo($info, $index) {
		$result = array();
		$result['success'] = false;
		if (!$info || empty($info) || $index < 0) {
			$result['success'] = false;
			$result['error'] = 'Data is null';
			return $result;
		}

		$data = [];
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			if (!isset($info)) {
				$result['success'] = false;
				$result['error'] = 'No data to update';
				return $result;
			}

			$recipe = &$data[$index];

			if (isset($info['RecipeFormat'])) {
				$recipe['RecipeFormat'] = $info['RecipeFormat'];
			}
			if (isset($info['RecipeName'])) {
				$recipe['RecipeName'] = $info['RecipeName'];
			}
			if (isset($info['RecipeDate'])) {
				$recipe['RecipeDate'] = $info['RecipeDate'];
			}

			if (isset($info['RecipeTime'])) {
				$recipe['RecipeTime'] = $info['RecipeTime'];
			}

			if (isset($info['RecipeQuantity'])) {
				$recipe['RecipeQuantity'] = $info['RecipeQuantity'];
				if ($recipe['RecipeQuantity'] <= 0) {
					$recipe['RecipeQuantity'] = 1;
				}
			}

			if (isset($info['Serving'])) {
				$recipe['Serving'] = $info['Serving'];
				if ($recipe['Serving'] <= 0) {
					$recipe['Serving'] = 1;
				}
			}
			$recipe['RecipeCost'] = $this->calculateRecipeCost($recipe, $info['Serving'], $info['MoneyRates']);
			$recipe['RecipeCost'] = floatval($recipe['RecipeCost'] . '');


			$recipe['RecipeCost'] = floatval($recipe['RecipeCost'] . '');
			$recipe['RecipeCost']=round($recipe['RecipeCost'], 2);

			$purchaseQuantity = 0;
			if (isset($info['RecipeQuantity']) && isset($info['Serving'])) {
				$purchaseQuantity = floatval(isset($info['RecipeQuantity']) * isset($info['Serving']));
				$purchaseQuantity = floatval(isset($info['Serving']));
			}

			$recipeSuccess = true;
			$recipeSuccess = file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT));

			if ($recipeSuccess) {
				$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
			} else {
				$result['success'] = false;
				$result['error'] = 'Cannot update data';
				return $result;
			}

			$result['success'] = true;
			$result['Index'] = $index;
			$result['Item'] = $this->setCategoryColor($recipe);

			return $result;
		}

		return $result;
	}
	private function validateDate($date, $format = 'Y-m-d') {
	    $d = DateTime::createFromFormat($format, $date);
	    return $d && $d->format($format) === $date;
	}
	public function reduceNutrientFromLog($reduceLog){
		$Format = $reduceLog['category'];
		$Ingredient = $reduceLog['product'];
		$StepQuantity = $reduceLog['reduceFromRecipe']['StepQuantity'];
		$recipeQuantity = $reduceLog['reduceFromRecipe']['recipeQuantity'];
		$serving = $reduceLog['reduceFromRecipe']['serving'];
		
		if (!isset($Ingredient) || !isset($Format) || trim($Ingredient) == '' || trim($Format) == '') {
			return false;
		}
            
        $inventory = $this->inventory->loadInventory($Format);
        $product = new Product($Format, $Ingredient, $inventory);
		if ($product->data) {
			$inventoryItem = $product->getData();
			$itemBefore = $inventoryItem;
			if ($StepQuantity > 0) {
                $useServing = $this->useServing($inventoryItem);
                $reduceNutrient = $recipeQuantity * ($useServing?$serving:1);
				$recipeAndStockRemainQuantity = $this->RecipeReduceStock($inventoryItem, ($StepQuantity), $reduceNutrient);
				$inventoryItem = $this->addProductSold($inventoryItem, $recipeAndStockRemainQuantity['ProductSold'], $recipeAndStockRemainQuantity['recipeQuantityNeed']);					
			}
			$inventoryItem = Product::checkStockChange($itemBefore, $inventoryItem);
			return $inventoryItem;
			// $inventory[$product->index] = $inventoryItem;
			// $this->inventory->saveInventory($Format, $inventory);
		}
		
		return false;
	}
	public function reduceNutrient($recipeIndex, $recipeQuantity, $serving, $recipeCost) {
		$result = array();
		$result['success'] = false;
		if ($recipeIndex < 0) {
			$result['success'] = false;
			$result['error'] = 'Don\'t know which recipe should be updated';
			return $result;
		}
		$inventories = [];

		$data = [];
		$data = $this->loadData();

		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			$recipe = $data[$recipeIndex];
			//pr($recipe);die('SSS');
			$outOfStock = false;
			for ($i = 0; $i < count($recipe['Steps']); $i++) {
				$step = $recipe['Steps'][$i];
                if (!isset($step['Ingredient']) || !isset($step['Format']) || trim($step['Ingredient']) == '' || trim($step['Format']) == '')
                    continue;
                if (!isset($inventories[$step['Format']])) {
                	$inventories[$step['Format']] = $this->inventory->loadInventory($step['Format']);
                }
                /*
                $product = new Product($step['Format'], $step['Ingredient'], $inventories[$step['Format']]);
				if ($product->data) {
					$inventoryItem = $product->getData();
					$itemBefore = $inventoryItem;
					if ($step['StepQuantity'] > 0) {
                        $useServing = $this->useServing($inventoryItem);
                        $reduceNutrient = $recipeQuantity * ($useServing?$serving:1);
						$recipeAndStockRemainQuantity = $this->RecipeReduceStock($inventoryItem, ($step['StepQuantity']), $reduceNutrient);
						$inventoryItem = $this->addProductSold($inventoryItem, $recipeAndStockRemainQuantity['ProductSold'], $recipeAndStockRemainQuantity['recipeQuantityNeed']);
					}
					$inventoryItem = Product::checkStockChange($itemBefore, $inventoryItem);
					$inventories[$product->category][$product->index] = $inventoryItem;
				}*/

				//Add reduce to update log-------
				$reduceLog = array(
					'category' => $step['Format'],
					'product' => $step['Ingredient'],
					'datetime' => date('Y-m-d H:i:s'),
					'reduceFromRecipe' => array(
						'StepQuantity' => $step['StepQuantity'],
						'recipeQuantity' => $recipeQuantity,
						'serving' => $serving
					)
				);
				$logs = $this->inventory->loadJson('../setting/update-log.json');
		        if (!$logs) $logs = array();
		        $logs[] = $reduceLog;
		        $this->inventory->saveJson('../setting/update-log.json', $logs);
			//---------------

			}
			if ($outOfStock) {
				$result['success'] = false;
				$result['error'] = 'Out of stock';
				return $result;
			} else {
				$success = true;
				/*foreach ($inventories as $category => $data) {
					$this->inventory->saveInventory($category, $data);
				}*/
				$result['success'] = true;
				$result['Inventory'] = $this->loadAllInventory();
				return $result;
			}
		}
	}
	public function RecipeReduceStock(&$inventoryItem, $stepQuantity, $purchaseQuantity){
		$stepQuantityNeed = round($stepQuantity * $purchaseQuantity);
		$StockRemain = $stepQuantityNeed;
		$ProductSold=0;
		$StockBuffer = 0;
		$reduceCompleted = false;
		//$sequence = array('StockRecipe', 'StockBulk', 'StockRetailLB', 'StockRetailOZ');
        $sequence = array("Recipe", "Bulk", "Shop");
        //echo "<br>========".$inventoryItem['Product']."============<br>";
        foreach ($sequence as $sequenceVal) {
        	if($reduceCompleted){
				break;
			}
			foreach ($inventoryItem['Retail'] as $retailIndex => $retailVal) {
				if($reduceCompleted){
					break;
				}
				if (!isset($retailVal['StockRetailShop'])){
					continue;
				}
				if($retailVal['StockRetailShop']<=0){
					continue;
				}
				$StockBuffer = (int)$retailVal['StockRetailShop'];
				if($retailVal['StockLocation'] == $sequenceVal) {
					$StockRemain = $StockRemain - $StockBuffer;
					if($StockRemain <= 0) {
						$ProductSold += ceil($StockRemain+$StockBuffer);
						$inventoryItem['Retail'][$retailIndex]['StockRetailShop'] = ceil(abs($StockRemain));
						$reduceCompleted = true;
					}
					else {
						$ProductSold += $StockBuffer;
						$inventoryItem['Retail'][$retailIndex]['StockRetailShop'] = 0;
					}
				}

				$StockRemain = abs($StockRemain);
				$StockBuffer = 0;
			}
        }
        return ['recipeQuantityRemain' => abs($StockRemain), 'ProductSold' => $ProductSold, 'recipeQuantityNeed' => $stepQuantityNeed];
	}
	
	public function msort($array, $key, $sort_flags = SORT_REGULAR, $order = SORT_ASC) {
	    if (is_array($array) && count($array) > 0) {
	        if (!empty($key)) {
	            $mapping = array();
	            foreach ($array as $k => $v) {
	                $sort_key = '';
	                if (!is_array($key)) {
	                    $sort_key = $v[$key];
	                } else {
	                    // @TODO This should be fixed, now it will be sorted as string
	                    foreach ($key as $key_key) {
	                        $sort_key .= $v[$key_key];
	                    }
	                    $sort_flags = SORT_STRING;
	                }
	                $mapping[$k] = $sort_key;
	            }
	            switch ($order) {
					case SORT_ASC:
						asort($mapping, $sort_flags);
						break;
					case SORT_DESC:
						arsort($mapping, $sort_flags);
						break;
				}
	            $sorted = array();
	            foreach ($mapping as $k => $v) {
	                $sorted[] = $array[$k];
	            }
	            return $sorted;
	        }
	    }
	    return $array;
	}
	
	
	public function stockingRecipe() {
		$recipeIndex = $_POST['Index'];
		$result = array();
		$result['success'] = true;
		if ($recipeIndex < 0) {
			$result['success'] = false;
			$result['error'] = 'Don\'t know which recipe should be updated';
			return $result;
		}
		$data = $this->loadData();
		if (count($data) <= 0) {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
			return $result;
		} else {
			$recipe = $data[$recipeIndex];
			$setting = $this->loadCategoryCssData();
			$format = $recipe['RecipeFormat'];
			$inventory = $this->inventory->loadInventory($format);
			if (!is_array($inventory)) {
				$result['success'] = false;
				$result['error'] = "{$format} not found";
				return $result;
			}
			$inventoryIndex = $this->findInventoryIndexByProduct($inventory, $recipe['RecipeName']);
			if ($inventoryIndex < 0) {
				$result['success'] = false;
				$result['error'] = "{$recipe['RecipeName']} not found";
				return $result;
			}
			$inventoryItem = $inventory[$inventoryIndex];
			$inventory[$inventoryIndex] = $this->addNewInventoryStock($inventoryItem, $format, $setting);
			$this->inventory->saveInventory($format, $inventory);
			return $result;
		}
	}

	private function findInventoryIndexAndInventoryNameByProductAndFormat($inventories, $product, $format) {
		$result['index'] = -1;
		$result['inventoryName'] = null;
		foreach ($inventories as $name => $inventory) {
			$found = false;
			foreach ($inventory as $ind => $item) {
				if (strtolower($item['Format']) == strtolower($format) && strtolower($item['Product']) == strtolower($product)) {
					$result['index'] = $ind;
					$result['inventoryName'] = $name;
					$found = true;
					break;
				}
			}
			if ($found) {
				break;
			}
		}
		return $result;
	}

	private function findInventoryIndexAndInventoryNameByProduct($inventories, $product) {
		$result['index'] = -1;
		$result['inventoryName'] = null;
		foreach ($inventories as $name => $inventory) {
			$found = false;
			foreach ($inventory as $ind => $item) {
				if (strtolower($item['Product']) == strtolower($product)) {
					$result['index'] = $ind;
					$result['inventoryName'] = $name;
					$found = true;
					break;
				}
			}
			if ($found) {
				break;
			}
		}
		return $result;
	}
// FUNCTION REDUCE SUPPLIER
    private function reduceSupplier($supplier, &$reduceValue, $reduceUnit)
    {
        $sequence = array('StockRecipe', 'StockBulk', 'StockRetailLB', 'StockRetailOZ');
        foreach ($sequence as $i => $key) {
            if (!isset($supplier[$key])) $supplier[$key] = 0;
            if ($supplier[$key] > 0) {
                $stock = (float)$supplier[$key];
                $stockRemain = $stock - $reduceValue;
                if ($stockRemain >= 0) {
                    $supplier[$key] = $stockRemain;
                    $reduceValue = 0;
                    continue;
                } else {
                    $supplier[$key] = 0;
                    $reduceValue = $stockRemain* (-1);
                }
            }
        }
        return $supplier;
    }
    private function getSupplierStock($supplier) {
    	return (float)$supplier['StockRetailLB'] + (float)$supplier['StockRecipe'] +
            (isset($supplier['StockRetailOZ'])?(float)$supplier['StockRetailOZ']:0);
    }
    private function updateInventoryStockAndCalculateRecipeRemainQuantity(&$inventoryItem, $stepQuantity, $purchaseQuantity) {
        $stepQuantityNeed = $stepQuantity * $purchaseQuantity;
        $willRecipeQuantity = $stepQuantityNeed;

        uasort($inventoryItem['Suppliers'], 'compareSupplier');
        $inventoryItem['Suppliers'] = array_values($inventoryItem['Suppliers']);

        $ProductSold=0;
        foreach ($inventoryItem['Suppliers'] as $key => $supplier) {
            if ($willRecipeQuantity == 0) {
                break;
            }
            $stockBefore = $this->getSupplierStock($supplier);
            $supplier = $this->reduceSupplier($supplier, $willRecipeQuantity, $supplier['StockUnit']);
            if ($supplier) {
            	$stockAfter = $this->getSupplierStock($supplier);
            	if ($stockAfter != $stockBefore && $stockAfter == 0) {
                    $supplier['DateUsageEnd'] = date('Y-m-d');
            	}
            	$bagOpen = $supplier['StockRetailOZ'] - floor($supplier['StockRetailOZ']);
            	if ($bagOpen > 0) {
            		$supplier['StockRecipe'] += $bagOpen/$inventoryItem['StockMin'];
            		$supplier['StockRetailOZ'] -= $bagOpen;
            	}
                $supplier['StockBulk'] = (string)round($supplier['StockBulk']);
                $supplier['StockRecipe'] = (string)round($supplier['StockRecipe']);
                $supplier['StockRetailLB'] = (string)round($supplier['StockRetailLB']);
                $supplier['StockRetailOZ'] = (string)round($supplier['StockRetailOZ']);
                $inventoryItem['Suppliers'][$key] = $supplier;
            }
        }
   //      for ($i = 0; $i < sizeof($inventoryItem['Suppliers']); $i++) {

        $ProductSold += ($stepQuantityNeed - $willRecipeQuantity);
        $inventoryItem['Suppliers'] = array_reverse($inventoryItem['Suppliers']);

        return ['recipeQuantityRemain' => $willRecipeQuantity, 'ProductSold' => $ProductSold, 'recipeQuantityNeed' => $stepQuantityNeed];
    }

/**** CONVERSION SHOULD BE REPLACE WITH UNIVERSAL FILE - Port from JS, so when you update JS, don't forget update these functions ****/
	private function calculateCostAvg ($supplier, $moneyRates) {
        $unit = $supplier['SupplierUnit'];
        $cost = $supplier['Cost'];
        $volume = $supplier['SupplierSize'];
        $unitSize = $supplier['StockUnit'];
        $currency = isset($supplier['Currency'])?$supplier['Currency']:'usd';
        $freight = isset($supplier['Freight'])?$supplier['Freight']:0;
		$costAvg = 0;

		if ($unit == null ) {
			$unit = '';
		}
		if ($volume == 0 || $volume == '' || $volume == null) {
			$volume = 0;
		}
		if ($cost == null || $cost == '') {
			$cost = 0;
		}

		if ($volume != 0) {
			$costAvg = floatval($cost) / Conversion::convertStockValue(floatval($volume), $unit, $unitSize);
		}

		/*$moneyRate = 1;
		if ($supplierName && strtolower($supplierName) == 'herbies') {
			$moneyRate = $moneyRates['cADUSDRate'];
		}
		if ($supplierName && strtolower($supplierName) == 'apo-rot') {
			$moneyRate = $moneyRates['eURUSDRate'];
		}*/
        switch($currency) {
            case 'cad':
                $moneyRate = $moneyRates['cADUSDRate'];
                break;
            case 'eur':
                $moneyRate = $moneyRates['eURUSDRate'];
                break;
            default:
                $moneyRate = 1;
        }
		$costAvg *= $moneyRate;
        $costAvg = $costAvg + $costAvg*$freight;
		$costAvg = round($costAvg, 3);

		return floatval($costAvg);
	}
    private function useServing($inventoryItem) {
        $isItem = strtolower($this->pickSupplier($inventoryItem['Suppliers'])['SupplierUnit']) == 'item';
        return !$isItem;
    }
    private function pickSupplier($suppliers) {
        $costPickSupplier = false;
        foreach ($suppliers as $supplier) {
        	if (!isset($supplier['CostPick']))
        		continue;
            if ($supplier['CostPick'] == 'yes') {
                $costPickSupplier = $supplier;
            }
            if ($supplier['CostPick'] == 'auto') {
                $costPickSupplier = $supplier;
                break;
            }
        }

        if ($costPickSupplier !== false)
            return $costPickSupplier;
        $sortedSuppliers = $suppliers;
        uasort($sortedSuppliers, 'compareSupplierToGetLatest');
        $earliestStock = 0;
        foreach ($sortedSuppliers as $supplier) {
            $costPickSupplier = $supplier;
            $fractionNumber = new FractionNumber($costPickSupplier['StockRetailLB'], isset($costPickSupplier['StockRecipe']) ? $costPickSupplier['StockRecipe'] : 0, $costPickSupplier['StockSize'], $costPickSupplier['StockUnit']);
            $stockBaseUnitValue = $fractionNumber->getBasicUnitValue();
            $earliestStock = $stockBaseUnitValue;
            if ($earliestStock > 0) {
                break;
            }
        }
        return $costPickSupplier;
    }
    private function calculateCostAvgLast($inventoryItem, $moneyRates) {
        $costAvgLast = 0;
        $pickedSupplier = $this->retail->pickSupplier($inventoryItem);
        if(!empty($pickedSupplier)) {
			//echo "<br>====".$inventoryItem['Product']."============<br>";
	        //echo "<pre>";print_r($pickedSupplier);
	        $supplierType = Retail::getSupplierType($pickedSupplier['SupplierUnit']);
	        $costAvgLast = $this->retail->calculateCostAvg($pickedSupplier, $supplierType['StockUnit']);
		}
        return $costAvgLast;
    }
	// private function calculateCostAvgLast($inventoryItem, $moneyRates) {

	private function calculateItemCost($inventoryItem, $step, $purchaseQuantity, $recipeItem, $moneyRates) {
		$itemCost = 0;
		$costAvgLast = $this->calculateCostAvgLast($inventoryItem, $moneyRates);
		if ($step['Format']=='Packaging') {
			$itemCost += $step['StepQuantity'] * $recipeItem['RecipeQuantity'] * $costAvgLast;
		} else {
			$itemCost = $step['StepQuantity'] * $purchaseQuantity * $costAvgLast;
		}
		return $itemCost;
	}

	private function calculateItemCostForNonInventory($step, $recipe, $purchaseQuantity, $recipeItem, $moneyRates) {
		$itemCost = 0;

// FACTORS FOR PRODUCTION TIME
		if (isset($step['Instruction']) && strtolower($step['Instruction']) == 'add label') {
			$itemCost = $step['StepQuantity'] * 0.25;
		} else if (isset($step['Instruction']) && strtolower($step['Instruction']) == 'production time') {
			if (floatval($recipeItem['RecipeQuantity']) > 0) {
				$itemCost = ($recipeItem['RecipeTime'] / floatval($recipeItem['RecipeQuantity'])) * 0.25;
			} else {
				$itemCost = 0;
			}
		}

		return $itemCost;
	}

 	private function countInTotal($productType) {
 		$ProductUnitNotCountInTotal = array('item');
 		return $productType && !in_array($productType, $ProductUnitNotCountInTotal);
 	}
	private function calculateItemCostTotal($recipe, $moneyRates) {
		$itemCostTotal = 0;
		for ($i = 0; $i < sizeof($recipe['Steps']); $i++) {
			$step = $recipe['Steps'][$i];
			if (!isset($step['Ingredient']))
				continue;
			$inventoryItem = $this->findInventoryItemByProductNameAndFormat($step['Ingredient'], $step['Format']);
			$purchaseQuantity = $recipe['RecipeQuantity']  * ($this->countInTotal($step['Format'])?$recipe['Serving']:1);
			if ($inventoryItem) {
				$itemCost = $this->calculateItemCost($inventoryItem, $step, $purchaseQuantity, $recipe, $moneyRates);
			} else {
				$itemCost = $this->calculateItemCostForNonInventory($step, $recipe, $purchaseQuantity, $recipe, $moneyRates);
			}
			$itemCostTotal += round($itemCost, 3);
		}
		return $itemCostTotal;
	}
	private function calculateRecipeCost($recipe, $purchaseQuantity, $moneyRates) {
		$recipeCost = $this->calculateItemCostTotal($recipe, $moneyRates);
		$recipeTime = $recipe['RecipeTime'] ? $recipe['RecipeTime'] : 0;
		$recipeQuantity = $recipe['RecipeQuantity'] ? $recipe['RecipeQuantity'] : 0;

		if ($recipeQuantity != 0) {
			$recipeCost /= $recipeQuantity;
			$recipeCost +=  (floatval($recipeTime) / floatval($recipeQuantity)) * 0.25;
		}

		$recipeCost=$recipeCost;

		return number_format($recipeCost, 3, '.', '');
	}

	private function findInventoryItemByProductNameAndFormat($productionName, $format) {
		if (!isset($this->allInventories))
			$this->allInventories = $this->loadAllInventory();
		$inventory = $this->allInventories;

		if ($productionName == null || $productionName == ''
				|| $format == null || $format == '') {
					return null;
				}

				$inventoryItem = null;
				for ($i = 0; $i < sizeof($inventory); $i++) {
					if (strtolower($inventory[$i]['Product']) == strtolower($productionName)
							&& strtolower($inventory[$i]['category']) == strtolower($format)) {
								$inventoryItem = $inventory[$i];
								break;
							}
				}

				return $inventoryItem;
	}


	/**** End port from JS ****/
/**** WHY THERE IS STOCKRETAILLB ****/
	private function calculateStockTotal($inventoryItem) {
		$stockTotal = 0;
		foreach ($inventoryItem['Suppliers'] as $supplier) {
			$stockTotal += floatval($supplier['StockRetailLB']);
		}
		return $stockTotal;
	}

	private function calculatePurchaseTotal($inventoryItem) {
		$purchaseTotal = 0;
		foreach ($inventoryItem['Suppliers'] as $supplier) {
			$purchaseTotal += floatval($supplier['Purchase']);
		}
		return $purchaseTotal;
	}

	private function standardlizeSteps(&$recipe) {
		for ($i = 0; $i < count($recipe['Steps']); $i++) {
			$recipe['Steps'][$i]['Step'] = ($i + 1) . '';
		}

		return $recipe;
	}

	private function isPureNutrientProduct($product) {
		$isPuretrientProduct = false;
		$productNameArray = explode(' - ', $product);

		if (count($productNameArray) > 1) {
			if (trim(strtolower($productNameArray[0])) == 'mixture') {
				$isPuretrientProduct = true;
			}
		}

		return $isPuretrientProduct;
	}

	private function findPureNutrientIndexByRecipeName($inventories, $recipeName) {
		$index = -1;
		$recipeNameArray = explode(' - ', $recipeName);
		$format = null;
		$product = null;

		if (count($recipeNameArray) > 1) {
			$format = trim($recipeNameArray[0]);
			$product = trim($recipeNameArray[1]);
		}

		foreach ($inventories['purenutrients'] as $ind => $item) {
			if (strtolower($item['Format']) == strtolower($format) && strtolower($item['Product']) == strtolower($product)) {
				$index = $ind;
				$found = true;
				break;
			}
		}

		return $index;
	}

	private function findPureNutrientIndexByRecipeNameAndFormat($inventories, $recipeName, $recipeFormat) {
		$index = -1;

		foreach ($inventories['purenutrients'] as $ind => $item) {
			if (strtolower($item['Format']) == strtolower($recipeFormat) && strtolower($item['Product']) == strtolower($recipeName)) {
				$index = $ind;
				$found = true;
				break;
			}
		}

		return $index;
	}

	private function updatePureNutrientInventoryStock(&$inventoryItem, $purchaseQuantity, $recipeCost) {
		uasort($inventoryItem['Suppliers'], 'compareSupplier');
		$inventoryItem['Suppliers'] = array_values($inventoryItem['Suppliers']);

		if (count($inventoryItem['Suppliers']) > 0) {
			$inventoryItem['Suppliers'][0]['StockRetailLB'] += $purchaseQuantity;
			$inventoryItem['Suppliers'][0]['Cost'] = $recipeCost;
			if ($inventoryItem['Suppliers'][0]['DateDelivery'] == '') {
				$inventoryItem['Suppliers'][0]['DateDelivery'] = date('Y-m-d');
			}
		}

		$inventoryItem['Suppliers'] = array_reverse($inventoryItem['Suppliers']);
	}

	private function findHorseInventoryIndexByProduct($inventories, $product) {
		$index = -1;

		$found = false;
		foreach ($inventories['equinesolution'] as $ind => $item) {
			if (strtolower($item['Product']) == strtolower($product)) {
				$index = $ind;
				$found = true;
				break;
			}
		}

		return $index;
	}

	private function findInventoryIndexByProduct($inventories, $product) {
		$index = -1;
		foreach ($inventories as $ind => $item) {
			if (strtolower($item['Product']) == strtolower($product)) {
				$index = $ind;
				break;
			}
		}

		return $index;
	}

	private function addNewHorseInventoryStock(&$inventoryItem, $purchaseQuantity, $recipeCost) {
		$inventoryItem['Suppliers'][] = [
				"Supplier" =>  "Equine Solution",
				"Quality" => "",
				"Produce" => "",
				"Volume"=> "1",
				"SupplierUnit" => "Item",
				"Cost" => $recipeCost,
				"Purchase" => 0,
				"Link" => "",
				"Lots" => "",
				"DateExpiration" => "",
				"Tracking" => "",
				"StockRetailLB" => $purchaseQuantity,
				"DateDelivery" => date('Y-m-d'),
		];
	}

	private function addNewInventoryStock($inventoryItem, $format, $setting) {
		$retail = new Retail();
		$date = new DateTime();
		if (!empty($setting[$format])) {
			$date->add(new DateInterVal("P{$setting[$format]}"));
		}
		$supplier = Template::createTemplateSupplier();
		$pickedSupplier = $retail->pickSupplier($inventoryItem);
		$supplier = array_merge($supplier, array_intersect_key($pickedSupplier, $supplier));
		$supplier['Purchase'] = '1';
		$supplier['DateOrdered'] = date('Y-m-d');
		$supplier['DateDelivery'] = date('Y-m-d');
		$supplier['DateExpiration'] = $date->format('Y-m-d');
		$inventoryItem['Suppliers'][] = $supplier;
		uasort($inventoryItem['Suppliers'], 'compareSupplierForStocking');
		$inventoryItem['Suppliers'] = array_values($inventoryItem['Suppliers']);
		$order = ['bulk', 'recipe', 'shop'];
		$addup = false;
		foreach ($order as $location) {
			foreach ($inventoryItem['Retail'] as $key => $variation) {
				if (strtolower($variation['StockLocation']) == $location) {
					$addup = true;
					$value = (float)$variation['StockRetailShop'];
					$stock = Conversion::convertStockValue((float)$supplier['SupplierSize']*(float)$supplier['Purchase'], $supplier['SupplierUnit'], 'gr');
					$inventoryItem['Retail'][$key]['StockRetailShop'] = (string)($value + $stock);
					break;
				}
			}
			if ($addup) break;
		}
		return $inventoryItem;
	}


// CONVERTION FORMULA FROM WEIGHT TO VOLUME (TO BE CANCEL)
	private function calculateOriginalOpenStockFromStockNeed($openStockNeed, $volume, $weight, $unit) {
		$originalOpenStock = 0;

		if ($unit == null ) {
			$unit = '';
		}
		if ($volume == 0 || $volume == '' || $volume == null) {
			$volume = 0;
		}
		if ($openStockNeed == null || $openStockNeed == '') {
			$openStockNeed = 0;
		}

		if ($weight == 0 || $weight == '' || $weight == null) {
			$weight = 0;
		}

		if ($volume != 0) {
			switch (strtolower($unit)) {
				case 'ml':
					$originalOpenStock = $openStockNeed / ((100/$weight) * 1);
					break;
				case 'gr':
					$originalOpenStock = $openStockNeed;
					break;
				default:
					$originalOpenStock = $openStockNeed;
					break;
			}
		}

		$originalOpenStock =  0.001 * intval($originalOpenStock*1000);



		return $originalOpenStock;

	}

	private function calculateOriginalStockFromStockNeed($stockNeed, $volume, $weight, $unit) {

		$originalStock = 0;

		if ($unit == null ) {
			$unit = '';
		}
		if ($volume == 0 || $volume == '' || $volume == null) {
			$volume = 0;
		}
		if ($stockNeed == null || $stockNeed == '') {
			$stockNeed = 0;
		}

		if ($weight == 0 || $weight == '' || $weight == null) {
			$weight = 0;
		}

		if ($volume != 0) {
			switch (strtolower($unit)) {
				case 'ml':
					$originalStock = $stockNeed / ($volume * (100/$weight) * 1);
					break;
				case 'gr':
					$originalStock = $stockNeed / ($volume);
					break;
				default:
					$originalStock = $stockNeed / ($volume);
					break;
			}
		}

		$originalStock =  0.001 * intval($originalStock*1000);

		return $originalStock;
	}

	private function calculateStockNeedFromOriginalStock($originalStock, $originalOpenStock, $volume, $weight, $unit) {
		$stockNeed = 0;
		$openStockNeed = 0;

		if ($unit == null ) {
			$unit = '';
		}
		if ($volume == 0 || $volume == '' || $volume == null) {
			$volume = 0;
		}
		if ($originalStock == null || $originalStock == '') {
			$originalStock = 0;
		}
		if ($originalOpenStock == null || $originalOpenStock == '') {
			$originalOpenStock = 0;
		}

		if ($weight == 0 || $weight == '' || $weight == null) {
			$weight = 0;
		}

		if ($volume != 0) {
			switch (strtolower($unit)) {
				case 'ml':
					$stockNeed = $originalStock * $volume * (100/$weight);
					$openStockNeed = $originalOpenStock * (100/$weight);
					break;
				case 'gr':
					$stockNeed = $originalStock * $volume;
					$openStockNeed = $originalOpenStock;
					break;
				default:
					$stockNeed = $originalStock * $volume;
					$openStockNeed = $originalOpenStock;
					break;
			}
		}

		$stockNeed =  floor($stockNeed);

		$openStockNeed =  floor($openStockNeed);

		return ['stockNeed' => $stockNeed, 'openStockNeed' => $openStockNeed];
	}

// CONVERTION FORMULA FROM WEIGHT TO VOLUME (TO BE CANCEL)
	private function createNewSupplier($product) {
		$supplier = array();

		$supplier["Supplier"] = "";
		$supplier["Quality"] = "";
		$supplier["Produce"] = "";
		$supplier["SupplierSize"] = "1";
		$supplier["SupplierUnit"] = "Item";
		$supplier["Cost"] = 0;
		$supplier["Purchase"] = 0;
		$supplier["Link"] = "";
		$supplier["Lots"] = "";
		$supplier["DateExpiration"] = "";
		$supplier["Tracking"] = "";
		$supplier["StockRetailLB"] = 0;
		$supplier["StockRecipe"] = 0;
		$supplier["DateDelivery"] = "";

		return $supplier;
	}
	private function createNewRecipe() {
		$recipe = array();
        $recipe["RecipeFormat"] = '';
        $recipe["RecipeName"] = '';
        $recipe["RecipeDate"] = date('Y-m-d');
        $recipe["RecipeQuantity"] = 0;
        $recipe["Serving"] = 0;
        $recipe["RecipeCost"] = 1;
        $recipe["RecipeTime"] = 1;
        $recipe["Steps"] = array();
        return $recipe;
	}
    public function addRecipes($recipes) {
    	$rs = array('success' => true);
    	$data = $this->loadData();
		if (count($data) <= 0) {
			$rs['success'] = false;
			$rs['error'] = 'Cannot update data';
    		return $rs;
		}
		$addedRecipes = array();
    	foreach ($recipes as $input) {
	    	if (empty($input['RecipeName'])) {
	    		$rs['success'] = false;
	    		$rs['error'] = 'RecipeName is empty';
	    		return $rs;
	    	}
	    	if (empty($input['RecipeFormat'])) {
	    		$rs['success'] = false;
	    		$rs['error'] = 'RecipeFormat is empty';
	    		return $rs;
	    	}
			$newRecipe = $this->createNewRecipe();
			$newRecipe['RecipeName'] = $input['RecipeName'];
			$newRecipe['RecipeFormat'] = $input['RecipeFormat'];
			$data[] = $newRecipe;
			$newRecipe['index'] = count($data)-1;
			$addedRecipes[] = $newRecipe;
    	}

		$update = $this->writeFile($data);
		if (!$update['success']) {
			$rs['success'] = false;
			$rs['error'] = $update['error'];
			return $rs;
		}
		$rs['recipes'] = $addedRecipes;
		return $rs;
    }
    private function writeFile($data) {
    	$result = array('success' => true);
		if (!file_put_contents($this->dataPath . '_temp', json_encode($data, JSON_PRETTY_PRINT))) {
			$result['success'] = false;
		}


		if ($result['success']) {
			$moveSuccess = rename($this->dataPath . '_temp', $this->dataPath);
		} else {
			$result['success'] = false;
			$result['error'] = 'Cannot update data';
		}
		return $result;
    }
	public function printRecipe($recipe) {
		$categoryCss = $this->loadCategoryCssData() ?? [];
		$inventories = array();
		$categoryCss = $categoryCss['CategoryCss'];
		foreach ($recipe['Steps'] as $index => $step) {
			foreach ($categoryCss as $category) {
				if (isset($step['Format']) && $step['Format'] == $category['category']) {
					$recipe['Steps'][$index]['Format_color'] = $category['style']['background-color'];
				}
			}
			if (isset($step['Format']) && !isset($inventories[$step['Format']])) {
				$inventories[$step['Format']] = $this->inventory->loadInventory($step['Format']);
			}
			if (isset($step['Format']) && isset($inventories[$step['Format']])) {
				$product = new Product($step['Format'], $step['Ingredient'], $inventories[$step['Format']]);
				if ($product->data) {
					$recipe['Steps'][$index]['product'] = $product->data;
					$bulkRetail = array_filter($product->data['Retail'], function($r) {
						return $r['StockLocation'] == 'Bulk';
					});
					$recipe['Steps'][$index]['bulkRetail'] = count($bulkRetail)?array_pop($bulkRetail):null;
				}
			}
		}
		$stepWeightTotal = 0;
		$stepQuantityTotal = 0;
		for ($i = count($recipe['Steps'])-1; $i >= 0 ; $i--) {
			$step = &$recipe['Steps'][$i];
			if (isset($step['SubTotal'])) {
				$step['StepWeight'] = $stepWeightTotal;
				$step['StepQuantity'] = $stepQuantityTotal;
				$stepWeightTotal = 0;
				$stepQuantityTotal = 0;
			} elseif (isset($step['Instruction'])) {
				$stepWeightTotal = 0;
				$stepQuantityTotal = 0;
			} elseif (isset($step['Ingredient'])) {
				if ($step['Format'] !== 'Packaging') {
					$stepWeightTotal += $this->getWeight($recipe, $step);
					$stepQuantityTotal += (float)$step['StepQuantity'];
				}
			}
		}
		$blocks = [];
		$block = ['instruction' => [], 'steps' => []];
		foreach ($recipe['Steps'] as $step) {
			if (isset($step['Instruction'])) {
				if ($block['instruction']) {
					$blocks[] = $block;
					$block = ['instruction' => [], 'steps' => []];
				}
				$block['instruction'] = $step;
			} else {
				$block['steps'][] = $step;
			}
		}
		if ($block['instruction']) {
			$blocks[] = $block;
		}
		require 'recipe-print-tpl.php';
	}
	private function getWeight($recipe, $step) {
		if ($step['StepMultiplier'] == 'true') {
			$stepWeightTotalForCondition = $step['StepQuantity'] * $recipe['RecipeQuantity'] * $recipe['Serving'];
		} else {
			$stepWeightTotalForCondition = $step['StepQuantity'] * $recipe['Serving'];
		}
		$weight = $stepWeightTotalForCondition>=4.5?round($stepWeightTotalForCondition):round($stepWeightTotalForCondition, 3);
		return $weight;
	}
    //add product sold weekly
    private function getDate($base = null) {
        if ($base == null)
            $base = time();
        if (date('N', $base) == 7) {
            return date('Y-m-d', $base);
        } else {
            return date('Y-m-d', strtotime('next sunday', $base));
        }
    }
    private function limitProductSoldWeekly($inventoryItem, $type = '') {
        $productSoldField = 'ProductSoldWeekly'.$type;
        if (is_array($inventoryItem[$productSoldField]) && count($inventoryItem[$productSoldField])) {
            $inventoryItem[$productSoldField] = array_filter(
                $inventoryItem[$productSoldField],
                function ($date) {
                    $now= new DateTime();
                    try {
                    	$target = new DateTime($date);
                    } catch (Exception $e) {
                    	return false;
                    }
                    if (!$target) {
                        return false;
                    }
                    $diff = (int)$now->diff($target)->format('%a');
                    return $diff < 365;
                },
                ARRAY_FILTER_USE_KEY
            );
        }
        return $inventoryItem;
    }
    public function addProductSold($inventoryItem, $productSold, $productSoldNeed) {
        $productSold = round($productSold, 2);
        $productSoldField = 'ProductSoldWeeklyRecipe';
        if (!isset($inventoryItem[$productSoldField])) {
        	$inventoryItem[$productSoldField] = array();
        }
        $dateKey = $this->getDate();
        if (!isset($inventoryItem[$productSoldField][$dateKey])) {
        	$inventoryItem[$productSoldField] = array($dateKey => 0) + $inventoryItem[$productSoldField];
        }
        $inventoryItem[$productSoldField][$dateKey] += $productSoldNeed;
        $inventoryItem[$productSoldField][$dateKey] = (string)floor($inventoryItem[$productSoldField][$dateKey]);
        $inventoryItem = $this->limitProductSoldWeekly($inventoryItem, 'Recipe');
        return $inventoryItem;
    }
    //add product sold weekly
}

function compareSupplier($s1, $s2) {
	return strcmp($s1['DateDelivery'], $s2['DateDelivery']);
}

function compareSupplierToGetLatest($s1, $s2) {
	return strcmp($s1['DateDelivery'], $s2['DateDelivery']);
}

function compareSupplierForStocking($s1, $s2) {
	return strcmp($s2['DateDelivery'], $s1['DateDelivery']);
}
if (!function_exists('pr')) {
	function pr($var) {
		$template = php_sapi_name() !== 'cli' ? '<pre>%s</pre>' : "\n%s\n";
		printf($template, print_r($var, true));
	}
}