<?php if (!defined('HTTP_SERVER')) die('You can not access this file directly!');
/**
  @licence GPL 2005-2010  The osCSS developers - osCSS Open Source E-commerce
  @portion code Copyright (c) 2002 osCommerce
  @package osCSS-2 <www http://www.oscss.org>
  @version 2.0.9
  @date  30/08/10, 10:32
  @author oscim <mail aurelien@oscim.fr> <www http://www.oscim.fr>
  @encode UTF-8
  @class currencies
*/

class stock
  implements ExtModPage, InterfaceModule {

  const FILENAME = FILENAME_STOCK;

  public static $code;

  public static $action;

  public static $list=array();
  /**
    @p array
  */
  public static $option_names;
  /**
    @p array
  */
  public static $options;
  /**
    @p bool on/off attribut ou stock classique
  */
  public static $by_attribute_stock;
  /**
    @p array check Qtpro
  */
  public static $investigation;
  /**
    @p string Name products
  */
  public static $product_name;
  /**
    @p int $db_quantity
  */
  public static $db_quantity;
  /**
    @p int Id product
  */
  public static $pID;

  /**
    class constructor
  */
  public function __construct() {
    self::$code=__CLASS__;



  }

  public function check_action($actions){
    global $messageStack;
    $DB=Database::getInstance();
//     $messageStack

    self::$action=$actions;



    if ($_SERVER['REQUEST_METHOD']=="GET") $VARS=$_GET;
    else  $VARS=$_POST;

    self::$pID=(int)$VARS['product_id'];

      if (!isset($VARS['action'])) $VARS['action']='';
      switch($VARS['action']){
	case 'Add' :
	  $inputok = true;
	  if (!(is_numeric(self::$pID))) $inputok = false;

	  while(list($v1,$v2)=each($VARS)) {
	    if (preg_match("/^option(\d+)$/",$v1,$m1)) {
	      if (is_numeric($v2) and ($v2==(int)$v2)) $val_array[]=$m1[1]."-".$v2;
	      else $inputok = false;
	    }
	  }

	  if (!(is_numeric($_POST['quantity']) and ($_POST['quantity']==(int)$_POST['quantity']))) $inputok = false;

	  if (($inputok)) {
	    sort($val_array, SORT_NUMERIC);
	    $val=join(",",$val_array);
	    $q=$DB->query($sql="select products_stock_id as stock_id from " . TABLE_PRODUCTS_STOCK . " where products_id=" . self::$pID . " and products_stock_attributes='" . $val . "' order by products_stock_attributes");

	    if ($q->__get('numRows')>0) {
	      $stock_item=$q->fetchAssoc();
	      $stock_id=$stock_item['stock_id'];

	      if ($_POST['quantity']=intval($_POST['quantity']))
		$DB->query($sql="update " . TABLE_PRODUCTS_STOCK . " set products_stock_quantity='" . (int)$_POST['quantity']. "' where products_stock_id='".$stock_id."'");

	      else
		$DB->query($sql="delete from " . TABLE_PRODUCTS_STOCK . " where products_stock_id='".$stock_id."'");

	    }
	    else
	      $DB->query($sql="insert into " . TABLE_PRODUCTS_STOCK . " values (0," .self::$pID . ",'$val','" . (int)$_POST['quantity'] . "' )");


	    $q=$DB->query("select sum(products_stock_quantity) as summa from " . TABLE_PRODUCTS_STOCK . " where products_id='" . self::$pID . "' and products_stock_quantity>0");
	    $list=tep_db_fetch_array($q);
	    $summa= (empty($list['summa'])) ? 0 : $list['summa'];
	    $DB->query("update " . TABLE_PRODUCTS . " set products_quantity=$summa where products_id=" . self::$pID);

	    if (($summa<1) && (STOCK_ALLOW_CHECKOUT == 'false')) {
	      $DB->query("update " . TABLE_PRODUCTS . " set products_status='0' where products_id=" . self::$pID);
	    }

	  }

	  tep_redirect(tep_href_link(self::FILENAME, 'product_id=' . self::$pID.(isset($_GET['forceajax']) || isset($_GET['forceview'])? '&forceview=true':'')  ) );
// 	if(!isset($_GET['origin'])) tep_redirect(tep_href_link(self::FILENAME, 'product_id=' . self::$pID.(isset($_GET['forceajax']) && isset($_GET['forceview']))? '&forceview=true':''));
// 	else tep_redirect(tep_href_link($_GET['origin']));

	break;
	case "Update":
	  tep_db_query("update " . TABLE_PRODUCTS . " set products_quantity=" . (int)$_POST['quantity'] . " where products_id=" . self::$pID);
	  if (($_POST['quantity']<1) && (STOCK_ALLOW_CHECKOUT == 'false')) {
	    tep_db_query("update " . TABLE_PRODUCTS . " set products_status='0' where products_id=" . self::$pID);
	  }
// exit;
	tep_redirect(tep_href_link(self::FILENAME, 'product_id=' . self::$pID.(isset($_GET['forceajax']) || isset($_GET['forceview'])? '&forceview=true':'') ));

// 	if(!isset($_GET['origin'])) tep_redirect(tep_href_link(self::FILENAME, 'product_id=' . self::$pID.(isset($_GET['forceajax']) && isset($_GET['forceview']))? '&forceview=true':''));
// 	else tep_redirect($_GET['origin']);

      break;
      case "Apply to all":
      break;
      default:

	self::load_db_values(self::$pID);
      /**
	Qt doctor
      */
      case "update_summary":
      break;
    }

    return self::$action;
  }

  public function get_header(){
  }


  public static function load_db_values($ID){
    global $languages_id;
    $DB=Database::getInstance();


    $q=$DB->query($sql="select products_name,products_options_name as _option,at.options_id as _option_id,products_options_values_name as _value,at.options_values_id as _value_id from ".
		      "".TABLE_PRODUCTS_DESCRIPTION." de, ".TABLE_PRODUCTS_ATTRIBUTES." at,".TABLE_PRODUCTS_OPTIONS." op,".TABLE_PRODUCTS_OPTIONS_VALUES." opv where ".
		      "at.products_id=de.products_id and ".
		      "at.products_id=" . (int)$ID . " and ".
		      "at.options_id=op.products_options_id and ".
		      "at.options_values_id=opv.products_options_values_id and ".
		      "de.language_id=" . (int)$languages_id . " and ".
		      "opv.language_id=" . (int)$languages_id . " and op.products_options_track_stock=1 and ".
		      "op.language_id=" . (int)$languages_id . " order by at.options_id, at.options_values_id");

    //list($product_name,$option_name,$option_id,$value,$value_id)
    if ($q->__get('numRows')>0) {
      self::$by_attribute_stock=1;
      while($list=$q->fetchAssoc()) {
	self::$options[$list['_option_id']][]=array($list['_value'],$list['_value_id']);
	self::$option_names[$list['_option_id']]=$list['_option'];
	self::$product_name=$list['products_name'];
      }
    }
    //Commented out so items with 0 stock will show up in the stock report.
    else {
      self::$by_attribute_stock=0;
      $q=$DB->query("select products_quantity,products_name from " . TABLE_PRODUCTS . " p,".TABLE_PRODUCTS_DESCRIPTION." pd where pd.products_id=" . (int)$ID . " and p.products_id=" . (int)$ID);
      $list=$q->fetchAssoc();
      self::$db_quantity=$list['products_quantity'];
      self::$product_name=stripslashes($list['products_name']);
    }

    self::$investigation = qtpro_doctor_investigate_product($ID);
//     return new objectInfo($currency_query->fetchAssoc() );
  }


  public static function load_db_stock(){
    $DB=Database::getInstance();
    $q=$DB->query("select * from " . TABLE_PRODUCTS_STOCK . " where products_id=" . self::$pID . " order by products_stock_attributes");
    return $q->fetchAllAssoc();
  }


  public function display_view(){
    switch(self::$action){
      case 'doctor';
	if(isset($_GET['action'])) $doctor_action = $_GET['action'];
	if(isset($_GET['pID'])) $products_id = $_GET['pID'];

	self::qtdoctor((int)$products_id);
	return tep_get_include_contents(self::$code.'.doctor');
      break;
      default:
	if ($_SERVER['REQUEST_METHOD']=="POST") $VARS=$_POST ;
	else  $VARS=$_GET;
	self::$pID=(int)$VARS['product_id'];
	return tep_get_include_contents(self::$code.'.edit');
    }
  }



  private static function qtdoctor($products_id){
    switch(self::$action){
      case 'examine':
	if(self::qtpro_doctor_product_healthy($products_id)){
	  self::$list[]=  '<span style="font-family: Verdana, Arial, sans-serif; font-size: 10px; color: green; font-weight: normal; text-decoration: none;"><b>Product is healthy</b><br /> The database entries for this products stock as they should.</span>';
	}else{
	  self::$list[]=  '<span style="font-family: Verdana, Arial, sans-serif; font-size: 10px; color: red; font-weight: normal; text-decoration: none;"><b>Product is sick</b><br /> The database entries for this products stock is messed up. This is why the table above looks messed up.</span>';
	}
      break;
      case 'amputate':
	self::$list[]= self::qtpro_doctor_amputate_bad_from_product($products_id).' database entries where amputated';
	self::$list[]= qtproUtility::update_summary_stock($products_id);
      break;
      case 'chuck_trash':
	print self::qtpro_chuck_trash().' database entries where identified as trash and deleted.';
      break;
      case 'update_summary':
	self::$list[]= qtproUtility::update_summary_stock($products_id);
	self::$list[]=  'The summary stock for the product was updated.';
      break;

      default:
	self::$list[]=  "<h3>QTPro Doctor - Overview</h3>";
	self::$list[]=  "You currently have <b>". self::qtpro_normal_product_count()."</b> products in your store.<br>";
	self::$list[]=  "<b>".self::qtpro_tracked_product_count()."</b> of them have options with tracked stock.<br>";
	self::$list[]=  "In the database we currently have <b>". self::qtpro_number_of_trash_stock_rows() . "</b> trash rows.";
	//print "<b>".qtpro_sick_product_count()."</b> of the producks with tracked stock is sick.<br><br>";
	self::$list[]= self::qtpro_doctor_formulate_database_investigation();
      break;

    }
  }

  /**
    Proposition acttion suite control du stock
  */
  public static function qtpro_doctor_formulate_product_investigation($facts_array, $formulate_style){
  $str_ret ='';
    switch($formulate_style){
      case 'short_suggestion':
	if($facts_array['any_problems']){
	  if($facts_array['summary_and_calc_stock_match'] != true && $facts_array['stock_entries_healthy'] != true){
	    $str_ret =__('the database entries for this products stock is messy and the summary stock calculation is wrong. '). __('please take a look at this ').'<a class="button" href="' . tep_href_link(self::FILENAME, 'product_id=' . $facts_array['id']) . '" >'.__('products stock').'</a>.';
	  }
	  elseif(!$facts_array['summary_and_calc_stock_match']){
	    $str_ret =__('the summary stock calculation is wrong. '). __('please take a look at this ').'<a  class="button" href="' . tep_href_link(self::FILENAME, 'product_id=' . $facts_array['id']) . ' " class="headerLink">'.__('products stock').'</a>.';
	  }
	  elseif(!$facts_array['stock_entries_healthy']){
	    $str_ret =__('the database entries for this products stock is messy. '). __('please take a look at this ').'<a  class="button" href="' . tep_href_link(self::FILENAME, 'product_id=' . $facts_array['id']) . ' " class="headerLink">'.__('products stock').'</a>.';
	  }else{
	    $str_ret ="Errorcatsh 754780+94322354678";
	  }
	}else{
	  $str_ret =__("this product is all ok.");
	}

      break;
      case 'detailed':
	//Create Header
	/*if($facts_array['any_problems']){
		$str_ret ='<span style="color:red; font-weight: bold; font-size:1.2em;">This product needs attention!</span><br /><br />';
	}else{
		$str_ret ='<span style="color:green; font-weight: bold;">This product is all ok.</span><br /><br />';
	}*/

	//Talk about summary and calc stock
	if($facts_array['summary_and_calc_stock_match']){
		$str_ret .='<span style="color:green; font-weight: bold; font-size:1.2em;">The stock quantity summary is ok</span><br />
		This means that the current summary of this products quantity, which is in the database, is the value we get if we calculates it from scratch right now.<br />
		<b>The Summary stock is: '. $facts_array['summary_stock'] .'</b><br /><br />';
	}else{
		$str_ret .='<span style="color:red; font-weight: bold; font-size:1.2em;">The stock quantity summary is NOT ok</span><br />
		This means that the current summary of this products quantity, which is in the database, isn\'t the value we get if we calculates it from scratch right now.<br />
		<b>The current summary stock is: '. $facts_array['summary_stock'] .'</b><br />
		<b>If we calculates it we get: '. $facts_array['calc_stock'] .'</b><br /><br />';
	}

	//Talk about the health of the stock entries
	if($facts_array['stock_entries_healthy']){
		$str_ret .='<span style="color:green; font-weight: bold; font-size:1.2em;">The options stock is ok</span><br />
		This means that the database entries for this product looks the way they should. No options are missing in any row. No option exist in any row where it should not.<br />
		<b>Total number of stock entries this product has: '. $facts_array['stock_entries_count'] .'</b><br />
		<b>Number of messy entries: '. $facts_array['sick_stock_entries_count'] .'</b><br />';

	}else{
		$str_ret .='<span style="color:red; font-weight: bold; font-size:1.2em;">'.__('the options stock is not ok').'</span><br />'.
		__('this means that at least one of the database entries for this product is messed up. either options are missing in rows or options exist in rows they should not.').'<br />'.
		'<b>'.__('total number of stock entries this product has: '). $facts_array['stock_entries_count'] .'</b><br />'.
		'<b>'.__('number of messy entries: '). $facts_array['sick_stock_entries_count'] .'</b><br /><br />';

		if(sizeof($facts_array['lacks_id_array']) > 0){
		  $str_ret .='<b>'.__('these options were missing in row(s):').'</b><br />';
		  foreach($facts_array['lacks_id_array'] as $lack_id){
		    $str_ret .= '<span style="color:red;"><b>'. tep_options_name($lack_id) .'</b></span><br />';
		  }
		  $str_ret .='<span style="color:blue; font-weight: bold;">'.__('possible solutions: ').'</span>'.__('delete the corresponding row(s) from the database or stop tracking the stock for that option.').'<br /><br />';
		}

		if(sizeof($facts_array['intruders_id_array']) > 0){
			$str_ret .= '<br /><b>'.__('these options exists in row(s) although they should not:').'</b><br />';
			foreach($facts_array['intruders_id_array'] as $intruder_id){
			  $str_ret .= '<span style="color:red;"><b>'. tep_options_name($intruder_id) .'</b></span><br />';
			}
			$str_ret .='<span style="color:blue; font-weight: bold;">'.__('possible solutions: ').'</span>'.__('delete the corresponding row(s) from the database or start tracking the stock for that option.').'<br /><br />';
		}

	}

	//Talk about automatic solutions
	if($facts_array['any_problems']){
	  $str_ret .= '<div class="button_nav">'.
		      '<span style="color:blue; font-weight: bold; font-size:1.2em;">'.__('automatic solutions avaliable') .':</span><br />';

	  if(!$facts_array['stock_entries_healthy'])
	    $str_ret .='<p><a class="button" href="' . tep_href_link(self::FILENAME, 'action=amputate&pID='.$facts_array['id'], 'NONSSL') . '" class="menuBoxContentLink" target="_blank">'.__('amputation (deletes all messy rows)').'</a></p>';

	  if(!$facts_array['summary_and_calc_stock_match'])
	    $str_ret .='<p><a class="button" href="' . tep_href_link(self::FILENAME, 'action=update_summary&pID='.$facts_array['id'], 'NONSSL') . '" class="menuBoxContentLink" target="_blank">'.__('set the summary stock to: '). $facts_array['calc_stock'] .'</a></p>';

	  $str_ret .='</div>';
	}


      break;
    }

    return $str_ret;
  }

  /*
  This function will take a string looking like "1-2,3-4,5-6" and return an array looking like:
  Array
  (
      [1] => 2
      [3] => 4
      [5] => 6
  )
  */
  private static function qtpro_products_attributes_string2array($products_attributes_string){
  $ret_array = array();

	  $optionchoise_array =explode(',', $products_attributes_string);// values in $option_choise_array looks like: '1-2'
	  //Now put them into $ret_array in a correct way:
	  foreach($optionchoise_array as $optionchoise){
		  $splitted_array = explode('-', $optionchoise);
		  $option = $splitted_array[0];
		  $choise = $splitted_array[1];

		  $ret_array[$option] = $choise;
	  }

  return $ret_array;
  }


  //-------------------------//
  //---  Doctor Functions  ---//
  //-------------------------//


  private static function qtpro_doctor_formulate_database_investigation(){
	  print "<p>Sick products in the database:</p>";
	  $prod_query = tep_db_query("SELECT products_id FROM " . TABLE_PRODUCTS);
	  while($product = tep_db_fetch_array($prod_query)){
		  $investigation= self::qtpro_doctor_investigate_product($product['products_id']);
		  if($investigation['any_problems']){
			  print '<p class="messageStackWarning">Product with ID '.$product['products_id'].': '.qtpro_doctor_formulate_product_investigation($investigation, 'short_suggestion').'</p>';
		  }
	  }
  }


  private static function qtpro_doctor_product_healthy($products_id){
	  $results = self::qtpro_doctor_investigate_product($products_id);
	  if($results['any_problems'] == false){
		  return true;
	  }else{
		  return false;
	  }
  }



  private static function qtpro_doctor_amputate_bad_from_product($products_id){
  $return_amputate_count = 0;

	  //MISSION CODENAME "Get information" STARTS HERE
	  //Get all products_stock entries for the product. ---------------------------------------
	  $attributes_stock_query = tep_db_query("SELECT products_stock_attributes, products_stock_id FROM " . TABLE_PRODUCTS_STOCK . " WHERE products_id = '" . $products_id . "'");

	  //Ops! a sub mission to possibly save work:
	  if (tep_db_num_rows($attributes_stock_query) == 0){
		  //This is normal if the product has NO strackstocked attributes
		  //BUT it can also happen for products WITH strackstocked attributes. Nothing in stock that is.
		  return $return_amputate_count; //The surgery is complete. Doctor says nothing to amputate :D
	  }
	  //Submission complete; let's continue

	  //Get the id for all options this product has and put them in the array: $products_options_array  ---------------------------------------
	  $products_options_query = tep_db_query("SELECT DISTINCT options_id FROM " . TABLE_PRODUCTS_ATTRIBUTES . " WHERE products_id = '" . $products_id . "'");
	  $products_options_array = array();
	  while ($products_option_id = tep_db_fetch_array($products_options_query)) {
		  $products_options_array[] =$products_option_id['options_id'];
	  }

	  //Get the id for all attributes which are tracked and put them in the array: $tracked_options_array  ---------------------------------------
	  $tracked_options_query = tep_db_query("SELECT DISTINCT products_options_id FROM " . TABLE_PRODUCTS_OPTIONS . " WHERE products_options_track_stock = 1");
	  $tracked_options_array = array();
	  while ($tracked_option_id = tep_db_fetch_array($tracked_options_query)) {
		  $tracked_options_array[] =$tracked_option_id['products_options_id'];
	  }
	  //Ok so now we can check if the option_id 8 is tracked by running: in_array(8, $tracked_options_array) =)

	  //MISSION CODENAME "Get information" ENDS HERE


	  //Check every row for errors
	  while ($products_stock_attributes = tep_db_fetch_array($attributes_stock_query)) {
		  $amputate_this = false;
		  $string_options_array = qtpro_products_attributes_string2options_array($products_stock_attributes['products_stock_attributes']);

		  //Now check for "intruder" errors (check for attributes which are there but should not as they are not stocktracked)
		  foreach($string_options_array as $option){
			  if(!in_array($option, $tracked_options_array)){
				  //aha! an "intruder"
				  $amputate_this = true; //The examination is complete. Doctor says this products_stock_id must be amputated :'(
			  }
		  }

		  //Now check for "lack" errors (check for attributes should be there, because they are stocktracked, but for some reason are not)
		  foreach($products_options_array as $products_option){
			  if(in_array($products_option, $tracked_options_array) && !in_array($products_option, $string_options_array)){
				  //aha! a "lack"
				  $amputate_this = true; //The examination is complete. Doctor says this products_stock_id must be amputated :'(
			  }
		  }

		  if($amputate_this){
			  tep_db_query("DELETE
						    FROM " . TABLE_PRODUCTS_STOCK . "
						    WHERE products_stock_id =". $products_stock_attributes['products_stock_id']);
			  $return_amputate_count++;
		  }
	  }

  return $return_amputate_count; //This will return the array with the amputate count.
  }


//------------------------------------------//
//---  Product Investigation Functions  ---//
//----------------------------------------//

  private static  function qtpro_product_exists($products_id){
	  $prod_query = tep_db_query("SELECT products_id FROM " . TABLE_PRODUCTS . " WHERE products_id = '" . $products_id . "'");
	  if (tep_db_num_rows($prod_query) == 0){
		  //Nothing was found so it did not exist.
		  return false;
	  }else{
		  return true;
	  }
  }







  private static function qtpro_products_summary_stock_is_as_calculated($products_id){
	  if(qtproUtility::calculate_summary_stock($products_id) == qtproUtility::get_products_summary_stock($products_id)){
		  return true;
	  }else{
		  return false;
	  }
  }


  //-------------------------//
  //---  Trash-Tools ---//
  //-------------------------//

  //This function will determine if the parameter row (taken from database table products_stock) is trash
  //It is if the products it liks to not exists.
  //The $row_array must contain the keys: 'products_id'
  private static function qtpro_stock_row_is_trash($row_array){
	  $prod_query = tep_db_query("SELECT products_id FROM " . TABLE_PRODUCTS . " WHERE products_id = '" . $products_id . "'");

	  if (self::qtpro_product_exists($row_array['products_id'])){
		  return false;
	  }else{
		  //The product this row links to does not exists. So it is trash then
		  return true;
	  }
  }

  //This function will count the number of strash rows in the database.
  //These rows should never come to exist but this is a good statistical fact for progammers as this indicate something is wrong
  private static function qtpro_number_of_trash_stock_rows(){
  $trash_count_ret = 0;

	  $products_stock_row_query = tep_db_query("SELECT products_id FROM " . TABLE_PRODUCTS_STOCK);
	  while($row = tep_db_fetch_array($products_stock_row_query)){
		  if(self::qtpro_stock_row_is_trash($row)){
			  $trash_count_ret++;
		  }
	  }

  return $trash_count_ret;
  }

  // This function will erase all strash rows in the database table for products option stock.
  private static function qtpro_chuck_trash(){
  $trash_count_ret = 0;

	  $products_stock_row_query = tep_db_query("SELECT products_stock_id, products_id FROM " . TABLE_PRODUCTS_STOCK);
	  while($row = tep_db_fetch_array($products_stock_row_query)){
		  if(self::qtpro_stock_row_is_trash($row)){
			  tep_db_query("DELETE FROM " . TABLE_PRODUCTS_STOCK . " WHERE products_stock_id=" . $row['products_stock_id']);
			  $trash_count_ret++;
		  }
	  }

  return $trash_count_ret;
  }

  //-------------------------//
  //---     Statistics    ---//
  //-------------------------//

  private static function qtpro_normal_product_count(){
	  $prod_query = tep_db_query("SELECT products_id FROM " . TABLE_PRODUCTS);
	  return tep_db_num_rows($prod_query);
  }

  private static function qtpro_tracked_product_count(){
  $count_ret = 0;
	  $prod_query = tep_db_query("SELECT products_id FROM " . TABLE_PRODUCTS);
	  while($product = tep_db_fetch_array($prod_query)){
		  if(qtproUtility::product_has_tracked_options($product['products_id'])){
			  $count_ret++;
		  }
	  }

  return $count_ret;
  }

  private static function qtpro_sick_product_count(){
  $count_ret = 0;
	  $prod_query = tep_db_query("SELECT products_id FROM " . TABLE_PRODUCTS);
	  while($product = tep_db_fetch_array($prod_query)){
		  if(!self::qtpro_doctor_product_healthy($product['products_id'])){
			  $count_ret++;
		  }
	  }

  return $count_ret;
  }

/** Interface module */

  function check() { return false; }
  function install() { return false; }
  function remove() { return false;  }
  function keys() { return false; }

}

?>