<?php
/**
 * phpaga
 *
 * Product management functionality.
 *
 * This file contains the necessary routines to manage products.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @version $Id$
 *
 * Copyright (c) 2005, Florian Lanthaler <florian@phpaga.net>
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in
 *      the documentation and/or other materials provided with the
 *      distribution.
 *
 *    * Neither the name of Florian Lanthaler nor the names of his
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


/**
 * Gets a product's information
 *
 * @param int    $prodID     Product ID (or product code, see $bycode)
 * @param bool   $bycode     If set to true then $prodID contains the product
 *                           code, otherwise the product ID
 *
 * @return array $peInfo     Array containing the results. A PhPagaError object on failure.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_getInfo($prodID, $bycode = false)
{
    $prodInfo = array();

    if (!isset($prodID) || (!strlen($prodID)))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_PRODUCT_INVALIDID);

    if ($bycode)
        $idfield = "products.prod_code";
    else
        $idfield = "products.prod_id";

    if (PHPAGA_DB_SYSTEM == "pgsql")
        $_times = "to_char(prod_created, 'yyyy-mm-dd hh24:mi:ss'::text) as prod_created, ".
            "to_char(prod_lastmod, 'yyyy-mm-dd hh24:mi:ss'::text) as prod_lastmod ";
    else
        $_times = "prod_created, prod_lastmod";

    $query = 'SELECT products.prod_id, prod_code, prod_name, prod_price, prod_consumption, prod_stock,
        products.prcat_id, prcat_title, '.$_times.'
        FROM products
        LEFT JOIN productcat ON productcat.prcat_id = products.prcat_id
        WHERE '.$idfield.' = ?';

    $d = new PhPagaDbData;

    $prodInfo = $d->queryRow($query, $prodID);

    if (PhPagaError::isError($prodInfo) || !count($prodInfo))
        return $prodInfo;

    phpaga_sanitizeArray($prodInfo);

    return $prodInfo;
}


/**
 * Checks if all fields of a product contain valid values.
 *
 * @param  array  $prodInfo  Array containing the product's information.
 *
 * @return bool   $errors    True. A PhPagaError object on failure.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_validdata($prodInfo)
{

    $errors = array();

    if (!is_array($prodInfo))
        $prodInfo = array($prodInfo);

    if (!isset($prodInfo["prod_code"]) || !strlen($prodInfo["prod_code"]))
        $errors[] = PHPAGA_ERR_PRODUCT_INVALIDCODE;

    if (!isset($prodInfo["prod_name"]) || !strlen($prodInfo["prod_name"]))
        $errors[] = PHPAGA_ERR_PRODUCT_INVALIDNAME;

    if (isset($prodInfo["prcat_id"]) && strlen($prodInfo["prcat_id"]) && !is_numeric($prodInfo["prcat_id"]))
        $errors[] = PHPAGA_ERR_PRCAT_INVALIDID;

    if (isset($prodInfo["prod_price"]) && strlen($prodInfo["prod_price"]) && !is_numeric($prodInfo["prod_price"]))
        $errors[] = PHPAGA_ERR_PRODUCT_INVALIDPRICE;

    if (isset($prodInfo["prod_consumption"]) && strlen($prodInfo["prod_consumption"]) && !is_numeric($prodInfo["prod_consumption"]))
        $errors[] = PHPAGA_ERR_PRODUCT_INVALIDCONSUMPTION;

    if (isset($prodInfo["prod_stock"]) && strlen ($prodInfo["prod_stock"]) && !is_numeric($prodInfo["prod_stock"]))
        $errors[] = PHPAGA_ERR_PRODUCT_INVALIDSTOCK;

    if (count($errors))
        return PhPagaError::raiseErrorByCode($errors);

    return true;
}


/**
 * Adds a product to the database
 *
 * @param array  $prodInfo  Array containing the product information
 *
 * @return int   $result    ID of the freshly inserted product. A PhPagaError object on failure.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_add($prodInfo)
{

    $prod_id = null;

    $result = phpaga_products_validdata($prodInfo);

    if (PhPagaError::isError($result))
        return $result;

    $d = new PhPagaDbData;

    $prod_id = $d->nextId("products_prod_id");

    if (!isset($prodInfo["prod_name"]) || !strlen($prodInfo["prod_name"]))
        $prodInfo["prod_name"] = NULL;

    if (!isset($prodInfo["prod_code"]) || !strlen($prodInfo["prod_code"]))
        $prodInfo["prod_code"] = NULL;

    if (!isset($prodInfo["prod_price"]) || !is_numeric($prodInfo["prod_price"]))
        $prodInfo["prod_price"] = NULL;

    if (!isset($prodInfo["prod_consumption"]) || !is_numeric($prodInfo["prod_consumption"]))
        $prodInfo["prod_consumption"] = NULL;

    if (!isset($prodInfo["prod_stock"]) || !is_numeric($prodInfo["prod_stock"]))
        $prodInfo["prod_stock"] = NULL;

    if (!isset($prodInfo["prcat_id"]) || !is_numeric($prodInfo["prcat_id"]))
        $prodInfo["prcat_id"] = NULL;

    $fields = array("prod_id" => $prod_id,
                    "prod_name" => $prodInfo["prod_name"],
                    "prod_code" => $prodInfo["prod_code"],
                    "prod_price" => $prodInfo["prod_price"],
                    "prod_consumption" => $prodInfo["prod_consumption"],
                    "prod_stock" => $prodInfo["prod_stock"],
                    "prcat_id" => $prodInfo["prcat_id"],
                    "prod_lastmod" => date("Y-m-d H:i:s")
        );

    $r = $d->insert('products', $fields);

    if (PhPagaError::isError($r))
        return $r;

    return $prod_id;
}


/**
 * Updates a product.
 *
 * @param array  $prodInfo Array containing the product information
 *
 * @return bool  $result   True, or PhPagaError
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_update($prodInfo)
{

    $result = phpaga_products_validdata($prodInfo);

    if (PhPagaError::isError($result))
        return $result;

    if (!isset($prodInfo["prod_name"]) || !strlen($prodInfo["prod_name"]))
        $prodInfo["prod_name"] = NULL;

    if (!isset($prodInfo["prod_code"]) || !strlen($prodInfo["prod_code"]))
        $prodInfo["prod_code"] = NULL;

    if (!isset($prodInfo["prod_price"]) || !is_numeric($prodInfo["prod_price"]))
        $prodInfo["prod_price"] = NULL;

    if (!isset($prodInfo["prod_consumption"]) || !is_numeric($prodInfo["prod_consumption"]))
        $prodInfo["prod_consumption"] = NULL;

    if (!isset($prodInfo["prod_stock"]) || !is_numeric($prodInfo["prod_stock"]))
        $prodInfo["prod_stock"] = NULL;

    if (!isset($prodInfo["prcat_id"]) || !is_numeric($prodInfo["prcat_id"]))
        $prodInfo["prcat_id"] = NULL;

    $fields = array("prod_name" => $prodInfo["prod_name"],
                    "prod_code" => $prodInfo["prod_code"],
                    "prod_price" => $prodInfo["prod_price"],
                    "prod_consumption" => $prodInfo["prod_consumption"],
                    "prod_stock" => $prodInfo["prod_stock"],
                    "prcat_id" => $prodInfo["prcat_id"],
                    "prod_lastmod" => date("Y-m-d H:i:s")
        );

    $d = new PhPagaDbData;
    $r = $d->update('products', $fields, 'prod_id = ?', array($prodInfo["prod_id"]));

    if (PhPagaError::isError($r))
        return $r;

    return true;
}


/**
 * Loads all product categories into an array.
 *
 * @param bool   $assoc       If true then load data into an associative array
 *                            (optional, defaults to false))
 *
 * @return int   $result       A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_getProdcats($assoc = false)
{
    $prcatInfo = null;

    $d = new PhPagaDbData;

    $r = $d->queryAll('SELECT prcat_id, prcat_title FROM productcat ORDER BY prcat_title');

    if (PhPagaError::isError($r))
        return $r;

    foreach ($r as $qrow) {

        phpaga_sanitizeArray($qrow);

        if ($assoc)
            $prcatInfo[$qrow['prcat_id']] = $qrow['prcat_title'];
        else
            $prcatInfo[] = $qrow;
    }

    return $prcatInfo;
}


/**
 * Add a new product category.
 *
 * @param  string  $prcat_title   Product category to be added
 *
 * @return int     $id            Category Id or a PhPagaError.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_addProdcat($prcat_title)
{

    if (!isset($prcat_title) || !strlen($prcat_title))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_PRCAT_INVALIDTITLE);

    $d = new PhPagaDbData;
    $id = $d->nextId('productcat_prcat_id');

    $r = $d->insert('productcat',  array('prcat_id' => $id,
                                         'prcat_title' => $prcat_title));
    if (PhPagaError::isError($r))
        return $r;

    return $id;
}


/**
 * Delete a product category.
 *
 * First check if this product category is needed by any table
 * relationship; delete it only if it is not needed.
 *
 * @param  int     $prcat_id     Product category to be deleted
 *
 * @return bool    $result       True if successful, PhPagaError otherwise.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_deleteProdcat($prcat_id)
{
    if (!isset($prcat_id) || !is_numeric($prcat_id))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_PRCAT_INVALIDID);

    $d = new PhPagaDbData;

    $n = $d->queryOneVal('SELECT COUNT(prod_id) FROM products WHERE prcat_id  = ?', $prcat_id);

    if (PhPagaError::isError($n))
        return $n;

    if ($n > 0)
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_DEL_DEPENDENCIES);

    $result = $d->execute('DELETE FROM productcat WHERE prcat_id = ?', $prcat_id);

    if (PhPagaError::isError($result))
        return $result;

    return true;
}


/**
 * Delete a product. A product can only be deleted if there are no
 * dependencies left.
 *
 * @param  int     $prod_id      Product ID
 *
 * @return bool    $result       True if successfull, PhPagaError otherwise.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_delete($prod_id)
{
    if (!isset($prod_id) || !is_numeric($prod_id))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_PRODUCT_INVALIDID);

    $d = new PhPagaDbData;

    $n = $d->queryOneVal('SELECT COUNT(prod_id) FROM material WHERE prod_id = ?', $prod_id);

    if (PhPagaError::isError($n))
        return $n;

    if ($n > 0)
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_DEL_DEPENDENCIES);

    $result = $d->execute('DELETE FROM products WHERE prod_id = ?', $prod_id);

    if (PhPagaError::isError($result))
        return $result;

    return true;
}


/**
 * Gets all products matching the search parmeters
 * (from $offset to $limit, if set)
 *
 * @param array  $rows      Array containing the results
 * @param int    $count     Number of records matching the query
 * @param array  $prodInfo  Product information
 * @param array  $prodIds   IDs of the resulting products
 * @param int    $order     Specifies the order by field
 *
 * @param int    $offset    Offset (optional)
 * @param int    $limit     Limit (optional)
 *
 * @return array $rows      Array containing the results. A PhPagaError object on failure.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_products_search(&$count,
                                &$prodIds,
                                $prodInfo,
                                $order = 0,
                                $offset = null,
                                $limit = null)
{

    $count = 0;
    $rows = array();
    $prodIds = array();
    $where = array();
    $qparam = array();

    $countquery = 'SELECT COUNT(products.prod_id) AS count_prod FROM products
                   LEFT JOIN productcat ON productcat.prcat_id = products.prcat_id ';

    if (PHPAGA_DB_SYSTEM == 'pgsql')
        $_times = "to_char(prod_created, 'yyyy-mm-dd hh24:mi:ss'::text) as prod_created,
            to_char(prod_lastmod, 'yyyy-mm-dd hh24:mi:ss'::text) as prod_lastmod ";
    else
        $_times = 'prod_created, prod_lastmod';

    $query = 'SELECT products.prod_id, prod_code, prod_name, prod_price, prod_consumption, prod_stock,
        products.prcat_id, prcat_title, '.$_times.'
        FROM products
        LEFT JOIN productcat ON productcat.prcat_id = products.prcat_id ';

    if (isset($prodInfo['prod_name']) && strlen($prodInfo['prod_name'])) {
        $where[] = 'products.prod_name like ?';
        $qparam[] = '%'.$prodInfo['prod_name'].'%';
    }

    if (isset($prodInfo['prod_code']) && strlen($prodInfo['prod_code'])) {
        $where[] = 'products.prod_code = ?';
        $qparam[] = $prodInfo['prod_code'];
    }

    if (isset($prodInfo['prcat_id']) && is_numeric($prodInfo['prcat_id'])) {
        $where[] = 'products.prcat_id = ?';
        $qparam[] = $prodInfo['prcat_id'];
    }

    if (count($where)) {
        $h = sprintf('WHERE %s ', implode(' AND ', $where));
        $countquery .= $h;
        $query .= $h;
    }

    $query .= ' ORDER BY prod_name ';

    $d = new PhPagaDbData;

    $count_pr = $d->queryOneVal($countquery, $qparam);

    if (!PhPagaError::isError($count_pr))
        $count = $count_pr;

    $products = $d->queryAll($query, $qparam, $offset, $limit);

    if (PhPagaError::isError($products))
        return $products;

    foreach($products as $qrow) {

        phpaga_sanitizearray($qrow);

        $rows[] = $qrow;
        $prodIds[] = $qrow['prod_id'];
    }

    phpaga_sanitizearray($rows);
    return $rows;
}

?>