<?php
/**
 * phpaga
 *
 * Operations functionality.
 *
 * This file contains the necessary routines to manage operations.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @version $Id: operations.php 753 2006-10-25 21:52:28Z florian $
 *
 * Copyright (c) 2002, 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.
 */

/**
 * Checks if all fields of an operation contain valid values.

 *
 * @param  array  $opInfo  Array containing the operation's information.
 *
 * @return array  $errors   Array containing error codes
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_validdata ($opInfo)
{

    $errors = array();

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

    if (!phpaga_checkdate($opInfo["op_startdate"]))
        $errors[] = PHPAGA_ERR_OP_STARTDATE;

    if (!phpaga_checkdate($opInfo["op_enddate"]))
        $errors[] = PHPAGA_ERR_OP_ENDDATE;

    if (!phpaga_checkhour ($opInfo["op_starthours"]))
        $errors[] = PHPAGA_ERR_OP_STARTHOURS;

    if (!phpaga_checkhour ($opInfo["op_endhours"]))
        $errors[] = PHPAGA_ERR_OP_ENDHOURS;

    if (!isset($opInfo["op_duration"]) || !strlen($opInfo["op_duration"]) ||
        !phpaga_checkduration ($opInfo["op_duration"]))
    {
        $errors[] = PHPAGA_ERR_OP_DURATION;
    }

    if (!isset($opInfo["op_desc"]) || !strlen(trim($opInfo["op_desc"])))
        $errors[] = PHPAGA_ERR_OP_DESC;

    if (isset($opInfo["prj_id"]) && !is_numeric($opInfo["prj_id"]))
        $errors[] = PHPAGA_ERR_PROJECT_INVALIDID;

    if (isset($opInfo["pe_id"]) && !is_numeric($opInfo["pe_id"]))
        $errors[] = PHPAGA_ERR_PERSON_INVALIDID;

    if (isset($opInfo["opcat_id"]) && !is_numeric($opInfo["opcat_id"]))
        $errors[] = PHPAGA_ERR_OPCAT_INVALIDID;

    return $errors;
}

/**
 * Adds an operation to the database
 *
 * @param array  $opInfo Array containing the operation information
 * @param int    &$op_id ID of the newly created record
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_add ($opInfo, &$op_id)
{

    $op_id = null;

    $result = phpaga_operations_validdata($opInfo);

    if (count($result) > 0)
        return $result;

    phpaga_db_connect($db);

    if (!isset($opInfo["op_desc"]) || !strlen($opInfo["op_desc"]))
        $opInfo["op_desc"] = NULL;

    if (!isset($opInfo["op_timestamp_start"]) || !strlen($opInfo["op_timestamp_start"]))
        $opInfo["op_timestamp_start"] = NULL;

    if (!isset($opInfo["op_timestamp_end"]) || !strlen($opInfo["op_timestamp_end"]))
        $opInfo["op_timestamp_end"] = NULL;

    if (!isset($opInfo["op_duration"]) || !strlen($opInfo["op_duration"]))
        $opInfo["op_duration"] = NULL;
    else
        $opInfo["op_duration"] = phpaga_duration2minutes($opInfo["op_duration"]);

    if (!isset($opInfo["op_billabletype"]) || ($opInfo["op_billabletype"] != 0))
        $opInfo["op_billabletype"] = 10;
    else
        $opInfo["op_billabletype"] = 0;

    $op_id = $db->nextId("operations_op_id");

    $fields = array("op_id" => $op_id,
                    "pe_id" => $opInfo["pe_id"],
                    "prj_id" => $opInfo["prj_id"],
                    "opcat_id" => $opInfo["opcat_id"],
                    "op_desc" => $opInfo["op_desc"],
                    "op_timestamp_start" => $opInfo["op_timestamp_start"],
                    "op_timestamp_end" => $opInfo["op_timestamp_end"],
                    "op_duration" => $opInfo["op_duration"],
                    "op_billabletype" => $opInfo["op_billabletype"],
                    "bill_id" => NULL
        );

    $result = $db->autoExecute("operations", $fields, DB_AUTOQUERY_INSERT);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;
    else
        return PHPAGA_ERR_NONE;
}


/**
 * Update an operation's information
 *
 * @param array  $opInfo Array containing the operation information
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_update($opInfo)
{

    $result = phpaga_operations_validdata($opInfo);

    if (count($result) > 0)
        return $result;

    phpaga_db_connect($db);

    /*  Note that prj_id and billing info do not get updated this way.
     *  This is intentional.
     */

    if (!isset($opInfo["op_desc"]) || !strlen($opInfo["op_desc"]))
        $opInfo["op_desc"] = NULL;

    if (!isset($opInfo["op_timestamp_start"]) || !strlen($opInfo["op_timestamp_start"]))
        $opInfo["op_timestamp_start"] = NULL;

    if (!isset($opInfo["op_timestamp_end"]) || !strlen($opInfo["op_timestamp_end"]))
        $opInfo["op_timestamp_end"] = NULL;

    if (!isset($opInfo["op_duration"]) || !strlen($opInfo["op_duration"]))
        $opInfo["op_duration"] = NULL;
    else
        $opInfo["op_duration"] = phpaga_duration2minutes($opInfo["op_duration"]);

    if (!isset($opInfo["op_billabletype"]) || ($opInfo["op_billabletype"] != 0))
        $opInfo["op_billabletype"] = 10;
    else
        $opInfo["op_billabletype"] = 0;

    $fields = array("pe_id" => $opInfo["pe_id"],
                    "opcat_id" => $opInfo["opcat_id"],
                    "op_desc" => $opInfo["op_desc"],
                    "op_timestamp_start" => $opInfo["op_timestamp_start"],
                    "op_timestamp_end" => $opInfo["op_timestamp_end"],
                    "op_duration" => $opInfo["op_duration"],
                    "op_billabletype" => $opInfo["op_billabletype"]
        );

    $result = $db->autoExecute("operations", $fields, DB_AUTOQUERY_UPDATE,
                               "op_id = ".$db->quoteSmart($opInfo["op_id"]));

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;
    else
        return PHPAGA_ERR_NONE;
}


/**
 * Gets a list of operation categories from the database and returns them
 * as the content of an array.
 *
 * @param array $opcatList   Array of operation categories
 *
 * @return int   $result     A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_getCategoryList (&$opcatList)
{
    $opcatList = array();

    phpaga_db_connect($db);

    $query = "SELECT opcat_id, opcat_title ".
        "FROM operationcat ".
        "ORDER BY opcat_title";

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    while ($qrow = $result->fetchRow())
    {
        phpaga_sanitizearray($qrow);
        $opcatList[$qrow["opcat_id"]] = $qrow["opcat_title"];
    }

    $result->free();
    return PHPAGA_ERR_NONE;
}


/**
 * Gets an operation's information.
 *
 * @param int    $opID    Operation's ID
 * @param array  $opInfo  Array containing the result.
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_getInfo ($opID, &$opInfo)
{
    $opInfo = array();

    if (!isset($opID) || (!is_numeric($opID)))
        return PHPAGA_ERR_OPERATION_INVALIDID;

    phpaga_db_connect($db);

    $query = "SELECT op_id, operations.pe_id, operations.opcat_id, ".
        "operations.prj_id, prj_title, opcat_title, ".
        "op_desc, op_timestamp_start, op_timestamp_end, ".
        "op_duration, bill_id, persons.pe_lastname, ".
        "persons.pe_firstname, op_billabletype ".
        "FROM operations ".
        "LEFT JOIN projects ON projects.prj_id = operations.prj_id ".
        "LEFT JOIN operationcat on operationcat.opcat_id = operations.opcat_id ".
        "LEFT JOIN persons on persons.pe_id = operations.pe_id ".
        "WHERE op_id = ".$db->quoteSmart($opID);

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    if ($result->numRows() < 1)
        return PHPAGA_ERR_DB_NO_ROWS;

    while ($qrow = $result->fetchRow())
    {
        $qrow["op_person"] =
            phpaga_persons_formatname($qrow["pe_lastname"],
                                      $qrow["pe_firstname"]);

        if (strlen($qrow["op_timestamp_start"])) {
            $qrow["op_startdate"] = date("Y-m-d", $qrow["op_timestamp_start"]);
            $qrow["op_starthours"] = date("H:i", $qrow["op_timestamp_start"]);
        } else {
            $qrow["op_startdate"] = "";
            $qrow["op_starthours"] = "";
        }

        if (strlen($qrow["op_timestamp_end"])) {
            $qrow["op_enddate"] = date("Y-m-d", $qrow["op_timestamp_end"]);
            $qrow["op_endhours"] = date("H:i", $qrow["op_timestamp_end"]);
        } else {
            $qrow["op_enddate"] = "";
            $qrow["op_endhours"] = "";
        }

        if (strlen($qrow["op_duration"])) {
            $qrow["op_duration"] = phpaga_minutes2duration($qrow["op_duration"]);
        }

        $opInfo = $qrow;
    }

    $result->free();
    return PHPAGA_ERR_NONE;
}


/**
 * Search operations matching search criteria.
 *
 * @param array  $rows      Array containing the results
 * @param int    $count     Number of records matching the query
 * @param string $duration  Total duration of matching operations
 * @param array  $opInfo    Operation information
 * @param array  $opIds     IDs of the resulting operations
 * @param int    $order     Specifies the order by field
 * @param int    $offset    Offset
 * @param int    $limit     Limit
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_search (&$rows,
                                   &$count,
                                   &$duration,
                                   &$opIds,
                                   $opInfo,
                                   $order = 0,
                                   $offset = "",
                                   $limit = "")
{

    $count = 0;
    $rows = array();
    $opIds = array();
    $where = array();
    $where_clause = "";
    $duration = "0:00";

    phpaga_db_connect($db);

    /* total number of matching records? */

    $countquery = "SELECT COUNT(op_id) AS count_op, ".
        "SUM(op_duration) as duration ".
        "FROM operations ".
        "LEFT JOIN projects ON projects.prj_id = operations.prj_id ";

    /* select matching records from operations */

    $query = "SELECT op_id, operations.prj_id, prj_title, opcat_title, ".
        "op_desc, op_timestamp_start, op_timestamp_end, ".
        "op_duration, bill_id, operations.pe_id, persons.pe_lastname, ".
        "persons.pe_firstname, projects.cpn_id_issuebill, ".
        "projects.prj_status, prjstat_title, prj_deadline, ".
        "case when (ph.phr_hourlyrate IS NOT NULL) then ph.phr_hourlyrate ".
        "ELSE case when prjmem_hourlyrate IS NOT NULL THEN prjmem_hourlyrate ELSE phn.phr_hourlyrate END END as applicable_hourlyrate, ".
        "(case when (ph.phr_hourlyrate IS NOT NULL) then ph.phr_hourlyrate ".
        "ELSE case when prjmem_hourlyrate IS NOT NULL THEN prjmem_hourlyrate ELSE phn.phr_hourlyrate END END * ";

    /* Mysql cannot cast to FLOAT */
    if (PHPAGA_DB_SYSTEM == 'mysql')
        $query .= "(op_duration/ 60))  AS amount ";
    else
        $query .= "(cast(op_duration AS FLOAT)/ 60))  AS amount ";

    $query .= "FROM operations ".
        "LEFT JOIN projects ON projects.prj_id = operations.prj_id ".
        "LEFT JOIN projectstatus ON projectstatus.prjstat_id = projects.prj_status ".
        "LEFT JOIN operationcat on operationcat.opcat_id = operations.opcat_id ".
        "LEFT JOIN project_members pm ON (pm.prj_id = operations.prj_id AND pm.pe_id = operations.pe_id) ".
        "LEFT JOIN persons on persons.pe_id = operations.pe_id ".
        "LEFT JOIN projects_hourlyrates ph ON (ph.opcat_id = operations.opcat_id and ph.prj_id = operations.prj_id AND ph.pe_id = operations.pe_id) ".
        "LEFT JOIN projects_hourlyrates phn ON (phn.opcat_id = operations.opcat_id and phn.prj_id = operations.prj_id AND phn.pe_id IS NULL) ".

    /* check whether the user has the permission to search for other
     * people's operations */

    $viewother = false;

    if (phpaga_user_hasperm(PHPAGA_PERM_VIEW_ALLTASKS) || phpaga_user_hasperm(PHPAGA_PERM_MANAGE_ALLTASKS))
        $viewother = true;
    else
        if (phpaga_user_hasperm(PHPAGA_PERM_VIEW_OTHERMEMTASKS))
            if (isset($opInfo["prj_id"]) && is_numeric($opInfo["prj_id"]))
                phpaga_project_is_member($opInfo["prj_id"], $_SESSION["auth_user"]["pe_id"], $viewother);

    if (!$viewother)
        $where[] = "operations.pe_id = ".$db->quoteSmart($_SESSION["auth_user"]["pe_id"]);
    else if (isset($opInfo["pe_id"]) && is_numeric($opInfo["pe_id"]))
        $where[] = "operations.pe_id = ".$db->quoteSmart($opInfo["pe_id"]);

    /* collect elements of the where clause */

    if (isset($opInfo["bill_id"]) && is_numeric($opInfo["bill_id"]))
        $where[] = "operations.bill_id = ".$db->quoteSmart($opInfo["bill_id"]);

    if (isset($opInfo["prj_id"]) && is_numeric($opInfo["prj_id"]))
        $where[] = "operations.prj_id = ".$db->quoteSmart($opInfo["prj_id"]);

    if (isset($opInfo["prjcat_id"]) && is_numeric($opInfo["prjcat_id"]))
        $where[] = "projects.prjcat_id = ".$db->quoteSmart($opInfo["prjcat_id"]);

    if (isset($opInfo["jcat_id"]) && is_numeric($opInfo["jcat_id"]))
        $where[] = "persons.jcat_id = ".$db->quoteSmart($opInfo["jcat_id"]);

    if (isset($opInfo["cpn_id"]) && is_numeric($opInfo["cpn_id"]))
        $where[] = "projects.cpn_id = ".$db->quoteSmart($opInfo["cpn_id"]);

    if (isset($opInfo["cpn_id_issuebill"]) && is_numeric($opInfo["cpn_id_issuebill"]))
        $where[] = "projects.cpn_id_issuebill = ".$db->quoteSmart($opInfo["cpn_id_issuebill"]);

    if (isset($opInfo["prj_status"]) && is_numeric($opInfo["prj_status"]))
        $where[] = "projects.prj_status = ".$db->quoteSmart($opInfo["prj_status"]);

    if (isset($opInfo["prj_billabletype"]) && is_numeric($opInfo["prj_billabletype"]))
        if ($opInfo["prj_billabletype"] == 0)
            $where[] = "(prj_billabletype IS NULL OR prj_billabletype = 0)";
        else
            $where[] = "prj_billabletype = ".$db->quoteSmart($opInfo["prj_billabletype"]);

    if (isset($opInfo["op_billed"]) && is_numeric($opInfo["op_billed"]))
    {
        switch ($opInfo["op_billed"])
        {
            case PHPAGA_BILL_NOTBILLED:
                $where[] = "operations.bill_id IS NULL";
                break;

            case PHPAGA_BILL_BILLED:
                $where[] = "operations.bill_id IS NOT NULL";
                break;

            default:
                break;
        }
    }

    if (isset($opInfo["opcat_id"]) && is_numeric($opInfo["opcat_id"]))
        $where[] = "operations.opcat_id = ".$db->quoteSmart($opInfo["opcat_id"]);

    if (isset($opInfo["op_desc"]) && ($opInfo["op_desc"] != ""))
        $where[] = "operations.op_desc LIKE '%".$db->escapeSimple($opInfo["op_desc"])."%'";

    if (isset($opInfo["op_startdatefrom"])
        && ($opInfo["op_startdatefrom"] != ""))
    {
        $where[] =
            "operations.op_timestamp_start >= ".
            strtotime ($opInfo["op_startdatefrom"]);
    }

    if (isset($opInfo["op_startdateto"])
        && ($opInfo["op_startdateto"] != ""))
    {
        $where[] =
            "operations.op_timestamp_start <= ".
            strtotime ($opInfo["op_startdateto"]." 23:59:59");
    }

    if (isset($opInfo["opidlist"]) && strlen($opInfo["opidlist"]))
        $where[] = sprintf("op_id IN (%s)", $opInfo["opidlist"]);

    /* build the where clause */
    if (count($where) > 0)
    {
        $query .= "WHERE ".implode(" AND ", $where)." ";
        $countquery .= "WHERE ".implode(" AND ", $where)." ";
    }

    $query .= " GROUP BY op_id, operations.prj_id, prj_title, opcat_title, op_desc, ".
        "op_timestamp_start, op_timestamp_end, op_duration, bill_id, operations.pe_id, ".
        "persons.pe_lastname, persons.pe_firstname, projects.cpn_id_issuebill, ".
        "projects.prj_status, prjstat_title, prj_deadline, prjmem_hourlyrate, ph.phr_hourlyrate, phn.phr_hourlyrate ".
        " ORDER BY ";

    /* build the order-by clause */
    /* check validity of order value, eventually set it to default */
    if (($order == "") || ($order == 0) || !is_numeric($order))
        $order = ORDER_OP_TIMESTAMP_START_DESC;

    switch ($order)
    {
        case ORDER_OP_PE_ASC:
            $query .= "pe_lastname ASC, pe_firstname ASC";
            break;
        case ORDER_OP_PE_DESC:
            $query .= "pe_lastname DESC, pe_firstname DESC";
            break;
        case ORDER_OP_PR_ASC:
            $query .= "prj_title ASC";
            break;
        case ORDER_OP_PR_DESC:
            $query .= "prj_title DESC";
            break;
        case ORDER_OP_OPCAT_ASC:
            $query .= "opcat_title ASC";
            break;
        case ORDER_OP_OPCAT_DESC:
            $query .= "opcat_title DESC";
            break;
        case ORDER_OP_DURATION_ASC:
            $query .= "op_duration ASC";
            break;
        case ORDER_OP_DURATION_DESC:
            $query .= "op_duration DESC";
            break;
        case ORDER_OP_TIMESTAMP_START_ASC:
            $query .= "op_timestamp_start ASC";
            break;
        default:
            $query .= "op_timestamp_start DESC ";
            break;
    }
//    die($query);
    /* first do the count stuff */

    $result = $db->query($countquery);

    if ((!DB::isError($result)) && ($result->numRows() > 0)
        && ($countrow = $result->fetchRow()))
    {
        $count = $countrow["count_op"];

        if (isset($countrow["duration"]) && is_numeric($countrow["duration"]))
            $duration = phpaga_minutes2duration ($countrow["duration"]);
    }

    /* limit the number of results starting from $offset if both $offset
     * and $limit are set and valid */

    if (isset($offset) && is_numeric($offset) && isset($limit)
        && is_numeric($limit) && ($limit > 0))

        $result = $db->limitQuery($query, $offset, $limit);
    else
        $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    if ($result->numRows() < 1)
        return PHPAGA_ERR_DB_NO_ROWS;

    $perm_tasks = phpaga_user_hasperm(PHPAGA_PERM_MANAGE_ALLTASKS);

    while ($qrow = $result->fetchRow())
    {

        phpaga_sanitizearray($qrow);

        /* The user can edit the task it has not been billed and
         * either she has overall task management rights or it is her
         * task */

        if ((!isset($qrow["bill_id"]) || !strlen($qrow["bill_id"]))
            && ($perm_tasks ||
                (isset($qrow["pe_id"])
                 && ($qrow["pe_id"] == $_SESSION["auth_user"]["pe_id"]))))

            $qrow["op_canedit"] = true;
        else
            $qrow["op_canedit"] = false;

        $qrow["op_duration_hrs"] =
            phpaga_minutes2duration ($qrow["op_duration"]);

        $qrow["op_person"] =
            phpaga_persons_formatname ($qrow["pe_lastname"],
                                       $qrow["pe_firstname"]);

        if (strlen($qrow["op_timestamp_start"]))
        {
            $qrow["op_startdate"] =
                date("Y-m-d", $qrow["op_timestamp_start"]);

            $qrow["op_starthours"] =
                date("H:i", $qrow["op_timestamp_start"]);
        }
        else
        {
            $qrow["op_startdate"] = "";
            $qrow["op_starthours"] = "";
        }

        if (strlen($qrow["op_timestamp_end"]))
        {
            $qrow["op_enddate"] =
                date("Y-m-d", $qrow["op_timestamp_end"]);

            $qrow["op_endhours"] =
                date("H:i", $qrow["op_timestamp_end"]);
        }
        else
        {
            $qrow["op_enddate"] = "";
            $qrow["op_endhours"] = "";
        }

        if ($qrow["op_duration"] != "")
        {
            $qrow["duration"] =
                phpaga_minutes2duration($qrow["op_duration"]);
        }

        $rows[] = $qrow;
        $opIds[] = $qrow["op_id"];
    }

    $result->free();
    return PHPAGA_ERR_NONE;
}


/**
 * Gets task category statistics
 *
 * @param array  $opInfo        Operation information
 * @param array  &$opcatStats   Array containing the results
 * @param int    $sum_duration  Total duration in minutes
 * @param bool   $groupby       Shall the results be grouped?
 *                              Possible groupings are:
 *                                by project: PHPAGA_OPCGRP_PROJECT
 *                                by person:  PHPAGA_OPCGRP_PERSON
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_getOpcatStats ($opInfo,
                                          &$opcatStats,
                                          &$sum_duration,
                                          $groupby = 0)
{
    $opcatStats = array();
    $sum_duration = 0;
    $where = array();
    $tmp_opcatStats = array();
    $tmp_prj_id  = array();
    $tmp_opcat_id = array();
    $dummy1 = 0;
    $dummy2 = 0;
    $opc = array();
    $prj = array();
    $query_extragrp = "";
    $query_extraorder = "";
    $query_extrajoin = "";

    phpaga_db_connect($db);


    $query = "SELECT operations.opcat_id, opcat_title, opcat_color, SUM(op_duration) AS opcat_duration ";

    switch($groupby)
    {
        case PHPAGA_OPCGRP_PROJECT:
            $query .=", operations.prj_id, prj_title ";
            $query_extragrp = "operations.prj_id, prj_title, ";
            $query_extraorder = "opcat_title, prj_title, ";
            break;

        case PHPAGA_OPCGRP_PERSON:
            $query .=", operations.pe_id, pe_lastname, pe_firstname ";
            $query_extragrp = "operations.pe_id, pe_lastname, pe_firstname, ";
            $query_extraorder = "opcat_title, pe_lastname, pe_firstname, ";
            $query_extrajoin = "LEFT JOIN persons p ON p.pe_id = operations.pe_id ";
            break;

        default:
            break;

    }

    $query .= "FROM operations ".
        "LEFT JOIN projects ON projects.prj_id = operations.prj_id ".
        "LEFT JOIN operationcat on operationcat.opcat_id = operations.opcat_id ".
        $query_extrajoin;

    /* collect elements of the where clause */

    if (isset($opInfo["pe_id"]) && is_numeric($opInfo["pe_id"]))
        $where[] = "operations.pe_id = ".$db->quoteSmart($opInfo["pe_id"]);

    if (isset($opInfo["prj_id"]) && is_numeric($opInfo["prj_id"]))
        $where[] = "operations.prj_id = ".$db->quoteSmart($opInfo["prj_id"]);

    if (isset($opInfo["cpn_id"]) && is_numeric($opInfo["cpn_id"]))
        $where[] = "projects.cpn_id = ".$db->quoteSmart($opInfo["cpn_id"]);

    if (isset($opInfo["opcat_id"]) && is_numeric($opInfo["opcat_id"]))
        $where[] = "operations.opcat_id = ".$db->quoteSmart($opInfo["opcat_id"]);

    if (isset($opInfo["op_desc"]) && strlen($opInfo["op_desc"]))
        $where[] = "operations.op_desc LIKE '%".$db->escapeSimple($opInfo["op_desc"])."%'";

    if (isset($opInfo["op_startdatefrom"]) && strlen($opInfo["op_startdatefrom"]))
    {
        $where[] =
            "operations.op_timestamp_start >= ".
            strtotime($opInfo["op_startdatefrom"]);
    }

    if (isset($opInfo["op_startdateto"]) && strlen($opInfo["op_startdateto"]))
    {
        $where[] =
            "operations.op_timestamp_start <= ".
            strtotime($opInfo["op_startdateto"]);
    }

    /* build where clause */

    if (count ($where) > 0)
        $query .= "WHERE ".implode(" AND ", $where)." ";

    $query .= "GROUP BY $query_extragrp ".
        "operations.opcat_id, opcat_title, opcat_color ".
        "ORDER BY $query_extraorder ".
        "opcat_duration DESC ";

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    if ($result->numRows() < 1)
        return PHPAGA_ERR_DB_NO_ROWS;

    while ($qrow = $result->fetchRow())
    {

        $sum_duration += $qrow["opcat_duration"];

        /* if any grouping is selected we need to fill the helper
         * arrays that will be required to create the matrix array
         */

        switch($groupby)
        {
            case PHPAGA_OPCGRP_PROJECT:

                $tmp_opcatStats["rows"][$qrow["opcat_id"]][$qrow["prj_id"]] = $qrow;

                if (!isset($tmp_prj_id[$qrow["prj_id"]])
                    || !is_array($tmp_prj_id[$qrow["prj_id"]]))
                {
                    $tmp_prj_id[$qrow["prj_id"]] = array("prj_id" => $qrow["prj_id"],
                                                         "prj_title" => $qrow["prj_title"],
                                                         "duration" => $qrow["opcat_duration"]);
                }
                else
                    $tmp_prj_id[$qrow["prj_id"]]["duration"] += $qrow["opcat_duration"];

                if (!isset($tmp_opcat_id[$qrow["opcat_id"]])
                    || !is_array($tmp_opcat_id[$qrow["opcat_id"]]))
                {
                    $tmp_opcat_id[$qrow["opcat_id"]] = array("opcat_id" => $qrow["opcat_id"],
                                                             "opcat_title" => $qrow["opcat_title"],
                                                             "duration" => $qrow["opcat_duration"]);
                }
                else
                    $tmp_opcat_id[$qrow["opcat_id"]]["duration"] += $qrow["opcat_duration"];

                break;


            case PHPAGA_OPCGRP_PERSON:

                $qrow["pe_person"] = phpaga_persons_formatname($qrow["pe_lastname"],
                                                               $qrow["pe_firstname"]);

                $tmp_opcatStats["rows"][$qrow["opcat_id"]][$qrow["pe_id"]] = $qrow;

                if (!isset($tmp_pe_id[$qrow["pe_id"]])
                    || !is_array($tmp_pe_id[$qrow["pe_id"]]))
                {
                    $tmp_pe_id[$qrow["pe_id"]] = array("pe_id" => $qrow["pe_id"],
                                                        "pe_person" => $qrow["pe_person"],
                                                        "duration" => $qrow["opcat_duration"]);
                }
                else
                    $tmp_pe_id[$qrow["pe_id"]]["duration"] += $qrow["opcat_duration"];

                if (!isset($tmp_opcat_id[$qrow["opcat_id"]])
                    || !is_array($tmp_opcat_id[$qrow["opcat_id"]]))
                {
                    $tmp_opcat_id[$qrow["opcat_id"]] = array("opcat_id" => $qrow["opcat_id"],
                                                             "opcat_title" => $qrow["opcat_title"],
                                                             "duration" => $qrow["opcat_duration"]);
                }
                else
                    $tmp_opcat_id[$qrow["opcat_id"]]["duration"] += $qrow["opcat_duration"];

                break;


            default:
                $opcatStats[] = $qrow;
                break;

        }
    }

    $result->free();

    switch($groupby)
    {
        case PHPAGA_OPCGRP_PROJECT:

            /* build matrix */

            $opcatStats["opcats"] = $tmp_opcat_id;
            $opcatStats["projects"] = $tmp_prj_id;

            foreach ($tmp_opcat_id as $dummy1 => $opc)
                foreach ($tmp_prj_id as $dummy2 => $prj)
                    if (!isset($tmp_opcatStats["rows"][$opc["opcat_id"]][$prj["prj_id"]])
                        || !is_array($tmp_opcatStats["rows"][$opc["opcat_id"]][$prj["prj_id"]]))

                        $opcatStats["rows"][$opc["opcat_id"]][$prj["prj_id"]] = array(
                            "opcat_title" => "",
                            "opcat_duration" => "",
                            "prj_id" => "",
                            "prj_title" => ""
                            );
                    else
                        $opcatStats["rows"][$opc["opcat_id"]][$prj["prj_id"]] =
                            $tmp_opcatStats["rows"][$opc["opcat_id"]][$prj["prj_id"]];
            break;


        case PHPAGA_OPCGRP_PERSON:

            /* build matrix */

            $opcatStats["opcats"] = $tmp_opcat_id;
            $opcatStats["persons"] = $tmp_pe_id;

            foreach ($tmp_opcat_id as $dummy1 => $opc)
                foreach ($tmp_pe_id as $dummy2 => $pe)
                    if (!isset($tmp_opcatStats["rows"][$opc["opcat_id"]][$pe["pe_id"]])
                        || !is_array($tmp_opcatStats["rows"][$opc["opcat_id"]][$pe["pe_id"]]))

                        $opcatStats["rows"][$opc["opcat_id"]][$pe["pe_id"]] = array(
                            "opcat_title" => "",
                            "opcat_duration" => "",
                            "pe_id" => "",
                            "peperson" => ""
                            );
                    else
                        $opcatStats["rows"][$opc["opcat_id"]][$pe["pe_id"]] =
                            $tmp_opcatStats["rows"][$opc["opcat_id"]][$pe["pe_id"]];
            break;

        default:
            break;

    }

    return PHPAGA_ERR_NONE;
}


/**
 * Delete a single operation.
 *
 * @param int    $opID    Operation ID
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_delete ($opID)
{
    if (!isset($opID) || !is_numeric($opID))
        return PHPAGA_ERR_OPERATION_INVALIDID;

    phpaga_db_connect($db);

    /* check for dependencies: an operation cannot be deleted if it
     * has already been invoiced */

    $query = "SELECT op_id ".
        "FROM operations ".
        "WHERE op_id = ".$db->quoteSmart($opID)." ".
        "AND bill_id IS NOT NULL; ";

    $result = $db->query($query);
    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    if ($result->numRows() > 0)
        return PHPAGA_ERR_DEL_DEPENDENCIES;

    $query = "SELECT lit_id ".
        "FROM lineitems ".
        "WHERE op_id = ".$db->quoteSmart($opID)." ".
        "AND bill_id IS NOT NULL; ";

    $result = $db->query($query);
    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    if ($result->numRows() > 0)
        return PHPAGA_ERR_DEL_DEPENDENCIES;

    $query = "DELETE FROM operations ".
        "WHERE op_id = ".$db->quoteSmart($opID);

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;
    else
        return PHPAGA_ERR_NONE;
}


/**
 * Calculate manhours. Manhours can be calculated by person, project, invoice,
 * company, operation category, or overall. A timeframe must be given, and a
 * display type (daily, calendar weeks, monthly).
 *
 * @param array  $rows      Array containing the results
 * @param array  $opInfo    Operation information (search parameters)
 * @param int    $type      Specifies the way data has to be grouped (displayed)
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_getManhours (&$rows,
                                        $opInfo,
                                        $type = PHPAGA_MANHOURS_DISPLAY_MONTH)
{
    $rows = array();
    $select = array();
    $where = array();
    $group = "";

    phpaga_db_connect($db);

    /* build the query depending on the selected type and on the underlying rdbms */
    switch ($type)
    {

        case PHPAGA_MANHOURS_DISPLAY_YEAR:
            /* year view */

            switch(PHPAGA_DB_SYSTEM)
            {

                case "pgsql":
                    $select[] = "TO_CHAR(op_timestamp_start::abstime::timestamp without time zone, 'iw YYYY') AS mhrs_date ";
                    $group = "GROUP BY TO_CHAR(op_timestamp_start::abstime::timestamp without time zone, 'iw YYYY') ";

                    if (isset($opInfo["op_startdatefrom"]) && strlen($opInfo["op_startdatefrom"])) {
                        $where[] =
                            "date_part('year', op_timestamp_start::abstime::timestamp without time zone) = ".
                            date("Y", strtotime($opInfo["op_startdatefrom"]));
                    }

                    break;

                case "mysql":
                    $select[] = "FROM_UNIXTIME(op_timestamp_start, '%v %x') AS mhrs_date ";
                    $group = "GROUP BY FROM_UNIXTIME(op_timestamp_start, '%v %x') ";

                    if (isset($opInfo["op_startdatefrom"]) && ($opInfo["op_startdatefrom"])) {
                        $where[] =
                            "FROM_UNIXTIME(op_timestamp_start, '%x') = ".
                            date("Y", strtotime($opInfo["op_startdatefrom"]));
                    }

                    break;

                default:
                    /* we should never reach this */
                    break;

            }

            break;

        default:
            /* month view */

            switch(PHPAGA_DB_SYSTEM)
            {

                case "pgsql":
                    $select[] = "TO_CHAR(op_timestamp_start::abstime::timestamp without time zone, 'YYYY-mm-dd') AS mhrs_date ";
                    $group = "GROUP BY TO_CHAR(op_timestamp_start::abstime::timestamp without time zone, 'YYYY-mm-dd') ";

                    if (isset($opInfo["op_startdatefrom"]) && strlen($opInfo["op_startdatefrom"])) {
                        $where[] =
                            "TO_CHAR(op_timestamp_start::abstime::timestamp without time zone, 'YYYY-mm') = '".
                            date("Y-m", strtotime($opInfo["op_startdatefrom"]))."'";
                    }

                    break;

                case "mysql":
                    $select[] = "FROM_UNIXTIME(op_timestamp_start, \"%Y-%m-%d\") AS mhrs_date ";
                    $group = "GROUP BY FROM_UNIXTIME(op_timestamp_start, \"%Y-%m-%d\") ";

                    if (isset($opInfo["op_startdatefrom"]) && strlen($opInfo["op_startdatefrom"])) {
                        $where[] =
                            "FROM_UNIXTIME(op_timestamp_start, '%Y-%m') = \"".
                            date("Y-m", strtotime($opInfo["op_startdatefrom"]))."\"";
                    }

                    break;

                default:
                    /* we should never reach this */
                    break;

            }

            break;
    }

    $select[] = "SUM(op_duration) AS mhrs_duration";

    /* collect elements of the where clause */

    if (isset($opInfo["pe_id"]) && is_numeric($opInfo["pe_id"]))
        $where[] = "operations.pe_id = ".$db->quoteSmart($opInfo["pe_id"]);

    if (isset($opInfo["bill_id"]) && is_numeric($opInfo["bill_id"]))
        $where[] = "operations.bill_id = ".$db->quoteSmart($opInfo["bill_id"]);

    if (isset($opInfo["prj_id"]) && is_numeric($opInfo["prj_id"]))
        $where[] = "operations.prj_id = ".$db->quoteSmart($opInfo["prj_id"]);

    if (isset($opInfo["cpn_id"]) && is_numeric($opInfo["cpn_id"]))
        $where[] = "projects.cpn_id = ".$db->quoteSmart($opInfo["cpn_id"]);

    if (isset($opInfo["opcat_id"]) && is_numeric($opInfo["opcat_id"]))
        $where[] = "operations.opcat_id = ".$db->quoteSmart($opInfo["opcat_id"]);

    /* build the select part */
    if (count ($select) > 0)
        $query = "SELECT ".implode(", ", $select)." ";

    $query .= "FROM operations ".
        "LEFT JOIN projects ON projects.prj_id = operations.prj_id ".
        "LEFT JOIN operationcat on operationcat.opcat_id = operations.opcat_id ".
        "LEFT JOIN persons on persons.pe_id = operations.pe_id ";

    /* build the where clause */
    if (count ($where) > 0)
        $query .= "WHERE ".implode(" AND ", $where)." ";

    $query .= " $group ORDER BY mhrs_date ";

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    while ($qrow = $result->fetchRow())
    {

        phpaga_sanitizearray($qrow);

        if (strlen($qrow["mhrs_duration"])) {
            $qrow["duration"] = phpaga_minutes2duration($qrow["mhrs_duration"]);
            $qrow["mhrs_duration"] = $qrow["mhrs_duration"] / 60;
        }

        $rows[] = $qrow;
    }

    $result->free();
    return PHPAGA_ERR_NONE;
}


/**
 * Loads all operation categories into an array. If opcat_id is
 * specified, only the matching opcat is loaded.
 *
 * @param array  $opcatInfo   Array containing the results
 * @param int    $opcat_id    Operation category ID (optional)
 * @param bool   $byid        If set to true, the returned array
 *                            is indexed by opcat_id (optional)
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_getOpcats (&$opcatInfo, $opcat_id = null, $byid = false)
{
    $opcatInfo = array();

    phpaga_db_connect($db);

    $query = "SELECT opcat_id, opcat_title, opcat_color, opcat_hourlyrate ".
        "FROM operationcat ";

    if (isset($opcat_id) && is_numeric($opcat_id))
        $query .= "WHERE opcat_id = ". $db->quoteSmart($opcat_id);

    $query .= " ORDER BY opcat_title ";

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    if ($result->numRows() < 1)
        return PHPAGA_ERR_DB_NO_ROWS;

    while ($qrow = $result->fetchRow())
    {
        phpaga_sanitizearray($qrow);

        if ($byid)
            $opcatInfo[$qrow["opcat_id"]] = $qrow;
        else
            $opcatInfo[] = $qrow;
    }

    $result->free();
    return PHPAGA_ERR_NONE;
}


/**
 * Add a new operation category.
 *
 * @param  string  $opcat_title        Operation category to be added
 * @param  string  $opcat_color        Color to be displayed in graphs (optional)
 * @param  float   $opcat_hourlyrate   Default hourly rate
 *
 * @return int     $result             A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_addOpcat ($opcat_title, $opcat_color = null, $opcat_hourlyrate = null)
{

    if (!isset($opcat_title) || !strlen ($opcat_title))
        return PHPAGA_ERR_OPCAT_INVALIDTITLE;

    if (strlen($opcat_hourlyrate) && !is_numeric($opcat_hourlyrate))
        return PHPAGA_ERR_INVALID_PARAMTYPE;

    phpaga_db_connect($db);

    $fields = array("opcat_id" => $db->nextId("operationcat_opcat_id"),
                    "opcat_title" => $opcat_title,
                    "opcat_color" => $opcat_color,
                    "opcat_hourlyrate" => $opcat_hourlyrate
        );

    $result = $db->autoExecute("operationcat", $fields, DB_AUTOQUERY_INSERT);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;
    else
        return PHPAGA_ERR_NONE;

}


/**
 * Update an operation category.
 *
 * @param  string  $opcat_id           Operation category ID
 * @param  string  $opcat_title        Title
 * @param  string  $opcat_color        Color to be displayed in graphs
 * @param  float   $opcat_hourlyrate   Default hourly rate
 *
 * @return int     $result             A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_operations_updateOpcat ($opcat_id, $opcat_title, $opcat_color, $opcat_hourlyrate)
{

    if (!isset($opcat_id) || !strlen ($opcat_id))
        return PHPAGA_ERR_OPCAT_INVALIDID;

    if (!isset($opcat_title) || !strlen ($opcat_title))
        return PHPAGA_ERR_OPCAT_INVALIDTITLE;

    if (strlen($opcat_hourlyrate) && !is_numeric($opcat_hourlyrate))
        return PHPAGA_ERR_INVALID_PARAMTYPE;

    if (!strlen(trim($opcat_color)))
        $opcat_color = null;

    phpaga_db_connect($db);

    $fields = array("opcat_title" => $opcat_title,
                    "opcat_color" => $opcat_color,
                    "opcat_hourlyrate" => $opcat_hourlyrate
        );

    $result = $db->autoExecute("operationcat", $fields, DB_AUTOQUERY_UPDATE,
                               "opcat_id = ".$db->quoteSmart($opcat_id));

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;
    else
        return PHPAGA_ERR_NONE;

}


/**
 * Delete an operation category.
 *
 * @param  int     $opcat_id    Operation category to be deleted
 *
 * @return int     $result      A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_operations_deleteOpcat ($opcat_id)
{
    if (!isset($opcat_id) || !is_numeric($opcat_id))
        return PHPAGA_ERR_OPCAT_INVALIDID;

    phpaga_db_connect($db);


    /* first check, if this opcat is needed by any table relationship
     * if it is not needed, then delete it, otherwise don't */

    $query = "SELECT op_id ".
        "FROM operations ".
        "WHERE opcat_id = ".$db->quoteSmart($opcat_id);

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    if ($result->numRows() > 0)
        return PHPAGA_ERR_DEL_DEPENDENCIES;

    $query = "DELETE FROM operationcat ".
        "WHERE opcat_id = ".$db->quoteSmart($opcat_id);

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;
    else
        return PHPAGA_ERR_NONE;
}


/**
 * Fetches the human cost for operations.
 *
 * The hourly rate is fetched according to the following precedence:
 *
 *  1. Member's hourly rate for a specific task category and project
 *  2. Member's hourly wage rate for the given project, independent of the task category
 *  3. Default rate for the given task category and project
 *
 * @param array  $opIds         Array containing operations IDs
 * @param array  $humancost     Array containing the cost information
 *
 * @return int   $result  A result code.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.2
 */

function phpaga_operations_gethumancost ($opIds, &$humancost)
{

    $humancost = array();
    $h_details = array();

    $humancost["total_amount"] = 0;
    $humancost["total_duration"] = 0;

    if (!isset($opIds) || !is_array($opIds) || !(count($opIds) > 0))
        return PHPAGA_ERR_INVALIDSEARCHPARAM;

    phpaga_db_connect($db);

    $query = "SELECT ".
        "op.pe_id, ".
        "pe_lastname, ".
        "pe_firstname, ".
        "SUM(op_duration) AS sum_duration, ".
        "SUM(case when (ph.phr_hourlyrate IS NOT NULL) then ph.phr_hourlyrate ".
        "ELSE case when prjmem_hourlyrate IS NOT NULL THEN prjmem_hourlyrate ELSE phn.phr_hourlyrate END END * ";

    /* MySQL cannot cast to FLOAT */
    if (PHPAGA_DB_SYSTEM == 'mysql')
        $query .= "(op_duration/ 60))  AS amount ";
    else
        $query .= "(cast(op_duration AS FLOAT)/ 60))  AS amount ";

    $query .= "FROM ".
        "operations op ".
        "LEFT JOIN project_members pm ON (pm.prj_id = op.prj_id AND pm.pe_id = op.pe_id) ".
        "LEFT JOIN persons pe ON pe.pe_id = op.pe_id ".
        "LEFT JOIN projects_hourlyrates ph ON (ph.opcat_id = op.opcat_id and ph.prj_id = op.prj_id AND ph.pe_id = op.pe_id) ".
        "LEFT JOIN projects_hourlyrates phn ON (phn.opcat_id = op.opcat_id and phn.prj_id = op.prj_id AND phn.pe_id IS NULL) ".
        "WHERE op_id IN (".implode(", ", $opIds).") ".
        "GROUP BY ".
        "op.pe_id, ".
        "pe_lastname, ".
        "pe_firstname ".
        "ORDER BY pe_lastname, pe_firstname ";

    $result = $db->query($query);

    if (DB::isError($result))
        return PHPAGA_ERR_DB_EXEC_QUERY;

    while ($qrow = $result->fetchRow())
    {
        phpaga_sanitizearray($qrow);

        $qrow["amount"] = (float) $qrow["amount"];
        $qrow["pe_person"] =
            phpaga_persons_formatname($qrow["pe_lastname"],
                                      $qrow["pe_firstname"]);
        $h_details[] = $qrow;
        $humancost["total_amount"] += $qrow["amount"];
        $humancost["total_duration"] += $qrow["sum_duration"];
    }

    $humancost["details"] = $h_details;
    $result->free();
    return PHPAGA_ERR_NONE;

}


/**
 * Sanitizes an array of operation Ids. Only the items containing an
 * Id are taken as valid.
 *
 * @param array $opids       Array of operation ids
 *
 * @return array $san        Sanitized array of operation ids or
 *                           false on error
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_operations_sanitizeopids ($opids)
{
    $san = array();

    if (!is_array($opids))
        return false;

    foreach ($opids as $o => $v)
        if (is_numeric($v) && !isset($san[$v]))
            $san[$v] = $v;

    return $san;
}

?>