<?PHP
#
#   FILE: EditMetadataSchema.php
#
#   Part of the Collection Workflow Integration System (CWIS)
#   Copyright 2013 Edward Almasy and Internet Scout Research Group
#   http://scout.wisc.edu/cwis/
#

# ----- EXPORTED FUNCTIONS ---------------------------------------------------

/**
* Get the metadata schema that is being edited.
* @param MetadataSchema $SchemaToUse Metadata schema that is edited for setting.
* @return Returns the metadata schema that is being edited.
*/
function GetMetadataSchema(MetadataSchema $SchemaToUse=NULL)
{
    static $Schema;

    if (!isset($Schema) || !is_null($SchemaToUse))
    {
        $Schema = $SchemaToUse;
    }

    return $Schema;
}

/**
* Get the list of privileges.
* @return Returns an array of all privileges.
*/
function GetPrivileges()
{
    static $Privileges;

    if (!isset($Privileges))
    {
        $PrivilegeFactory = new PrivilegeFactory();
        $Privileges = $PrivilegeFactory->GetPrivileges();
    }

    return $Privileges;
}

/**
* Get the list of all metadata fields supported in the privileges associated
* with metadata schemas.
* @return Returns an array of supported metadata fields.
*/
function GetSupportedFields()
{
    static $SupportedFields;

    if (!isset($SupportedFields))
    {
        $Schema = GetMetadataSchema();
        $SupportedFieldTypesInOrder = array(
            MetadataSchema::MDFTYPE_USER,
            MetadataSchema::MDFTYPE_FLAG,
            MetadataSchema::MDFTYPE_NUMBER,
            MetadataSchema::MDFTYPE_DATE,
            MetadataSchema::MDFTYPE_TIMESTAMP);

        $SupportedFields = array();

        foreach ($SupportedFieldTypesInOrder as $Type)
        {
            $SupportedFields += $Schema->GetFields($Type);
        }
    }

    return $SupportedFields;
}

/**
* Get the list of supported operators.
* @return Returns an array of the supported operators.
*/
function GetSupportedOperators()
{
    static $Operators = array("==", "!=", "<", ">");

    return $Operators;
}

# ----- LOCAL FUNCTIONS ------------------------------------------------------

/**
* Get the page with necessary parameters when returning to the DBEditor page.
* @param mixed $Value MetadataSchema object, MetadataField object, or a schema
*      ID.
* @return Returns the page to return to.
*/
function GetReturnToPage($Value)
{
    $Suffix = "";

    # get the suffix from a metadata schema if not using the default schema
    if ($Value instanceof MetadataSchema)
    {
        if ($Value->Id() != MetadataSchema::SCHEMAID_DEFAULT)
        {
            $Suffix = "&SC=" . urlencode($Value->Id());
        }
    }

    # use the value directly if not using the default schema
    else if (!is_null($Value) && $Value != MetadataSchema::SCHEMAID_DEFAULT)
    {
        $Suffix = "&SC=" . urlencode($Value);
    }

    return "DBEditor" . $Suffix;
}

/**
* Construct a new privilege set from the given array of form data.
* @param array $FormData An array of form data. This variable will be modified
*       by reference.
* @return Returns a PrivilegeSet object.
* @throws Exception if invalid data is given.
*/
function GetPrivilegeSetFromFormData(array &$FormData)
{
    $NewPrivilegeSet = new PrivilegeSet();
    $Privileges = GetPrivileges();
    $SupportedFields = GetSupportedFields();
    $SupportedOperators = GetSupportedOperators();

    while (count($FormData))
    {
        # extract the form fields
        $SubjectField = array_shift($FormData);
        $OperatorField = array_shift($FormData);
        $ValueSelectField = array_shift($FormData);
        $ValueInputField = array_shift($FormData);

        # privilege condition
        if ($SubjectField == "current_user")
        {
            # invalid privilege ID
            if (!isset($Privileges[$ValueSelectField]) || is_null($ValueSelectField))
            {
                throw new Exception("Invalid privilege (".$ValueSelectField.")");
            }

            $NewPrivilegeSet->AddPrivilege($ValueSelectField);
        }

        # metadata field condition
        else if (is_numeric($SubjectField))
        {
            # invalid field ID
            if (!isset($SupportedFields[$SubjectField]) || is_null($SubjectField))
            {
                throw new Exception("Invalid or unsupported field (".$SubjectField.")");
            }

            # invalid operator
            if (!in_array($OperatorField, $SupportedOperators))
            {
                throw new Exception("Invalid or unsupported operator (".$OperatorField.")");
            }

            $MetadataField = $SupportedFields[$SubjectField];

            switch ($MetadataField->Type())
            {
                case MetadataSchema::MDFTYPE_USER:
                    $Value = NULL;
                    break;
                case MetadataSchema::MDFTYPE_FLAG:
                    $Value = 1;
                    break;
                case MetadataSchema::MDFTYPE_TIMESTAMP:
                case MetadataSchema::MDFTYPE_DATE:
                case MetadataSchema::MDFTYPE_NUMBER:
                    $Value = $ValueInputField;
                    break;
                default:
                    $Value = NULL;
                    break;
            }

            $NewPrivilegeSet->AddCondition($MetadataField, $Value, $OperatorField);
        }

        # entering a nested privilege set
        else if ($SubjectField == "set_entry")
        {
            # the logic is invalid
            if ($ValueSelectField != "AND" && $ValueSelectField != "OR")
            {
                throw new Exception("Invalid privilege set logic (".$ValueSelectField.")");
            }

            $NestedPrivilegeSet = GetPrivilegeSetFromFormData($FormData);

            # only add the nested privilege set if it's not empty. use 1
            # because the logic is in the privilege info array
            if (count($NestedPrivilegeSet->GetPrivilegeInfo()) > 1)
            {
                $NestedPrivilegeSet->AllRequired($ValueSelectField == "AND");
                $NewPrivilegeSet->AddSet($NestedPrivilegeSet);
            }
        }

        # exiting a privilege set
        else if ($SubjectField == "set_exit")
        {
            break;
        }

        # unknown condition type
        else
        {
            throw new Exception("Unknown condition type");
        }
    }

    return $NewPrivilegeSet;
}

# ----- MAIN -----------------------------------------------------------------

PageTitle("Edit Metadata Schema");

# check authorization
if (!CheckAuthorization(PRIV_SYSADMIN, PRIV_COLLECTIONADMIN)) {  return;  }

# construct the schema object
$SchemaId = GetArrayValue($_GET, "SC", MetadataSchema::SCHEMAID_DEFAULT);
$H_Schema = new MetadataSchema($SchemaId);
GetMetadataSchema($H_Schema);

# the action to be performed, if any
$Action = GetFormValue("F_Submit");

# variables for holding privilege errors
$H_ViewingPrivilegesError = NULL;
$H_AuthoringPrivilegesError = NULL;
$H_EditingPrivilegesError = NULL;

# cancel editing
if ($Action == "Cancel")
{
    # go back to the list of fields for the schema
    $AF->SetJumpToPage(GetReturnToPage($H_Schema));
    return;
}

# update an existing field (field checks are above)
else if ($Action == "Save Changes")
{
    # update each type of privilege
    foreach (array("View", "Author", "Edit") as $PrivilegeType)
    {
        try
        {
            # get the new privilege set
            $Data = GetFormValue("F_".$PrivilegeType."ingPrivileges", array());
            $NewPrivilegeSet = GetPrivilegeSetFromFormData($Data);

            # get the specified top-level logic
            $TopLevelLogic = GetFormValue("F_".$PrivilegeType."ingPrivilegesLogic", "OR");

            # AND logic specified
            if ($TopLevelLogic == "AND")
            {
                $NewPrivilegeSet->AllRequired(TRUE);
            }

            # update the privileges
            $H_Schema->{$PrivilegeType."ingPrivileges"}($NewPrivilegeSet);
        }

        catch (Exception $Exception)
        {
            # couldn't update the privileges
            ${"H_".$PrivilegeType."ingPrivilegesError"} = $Exception->getMessage();
        }
    }

    # go back to the list of fields for the schema if there were no errors
    if (is_null($H_ViewingPrivilegesError)
        && is_null($H_AuthoringPrivilegesError)
        && is_null($H_EditingPrivilegesError))
    {
        $AF->SetJumpToPage(GetReturnToPage($H_Schema));
        return;
    }
}
