<?PHP
#
#   FILE: DBAddFieldComplete.php
#
#   FUNCTIONS PROVIDED:
#
#   FUNCTIONS EXPECTED:
#       None
#
#   Part of the Collection Workflow Integration System (CWIS)
#   Copyright 2011 Internet Scout Project
#   http://scout.wisc.edu/
#

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

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

# populate the tree field with data from specified file
function PopulateTree($Field, $FileName)
{
    $DB = new SPTDatabase();

    if (!file_exists($FileName))
        return FALSE;

    $FP = fopen($FileName, 'r');

    while (!feof($FP))
    {
        $ClassificationName = fgets($FP, 16384);

        # last line read, exit
        if (empty($ClassificationName))
            break;

        $NewClass = new Classification(NULL, $ClassificationName,
                            $Field->Id());
    }
    return TRUE;
}

/**
 * Take data from the input form on DBAddField and save it into a Field object
 * Checks completeness of required fields for data that is about to go into the database,
 * But allows incomplete or incorrect field specifications as the field is edited.
 */
function SaveFormData()
{
    global $Field, $F_FieldType, $F_FieldName, $F_Enabled, $F_Optional,
        $F_Viewable, $F_DefaultValue,$F_UsesQualifiers,$F_ShowQualifiers,
        $F_HasItemLevelQualifiers, $F_DefaultQualifier,
        $F_IncludeInKeywordSearch, $F_IncludeInAdvancedSearch,
        $F_IncludeInSortOptions, $F_SearchWeight, $F_TextFieldSize,
        $F_MaxLength, $F_MinValue, $F_MaxValue, $F_DateFormat,
        $F_ParagraphRows, $F_ParagraphCols, $F_FlagOnLabel, $F_FlagOffLabel,
        $F_AllowMultiple, $F_Description, $F_DefaultAltText, $F_MaxHeight,
        $F_MaxWidth, $F_MaxPreviewHeight, $F_MaxPreviewWidth,
        $F_MaxThumbnailHeight, $F_MaxThumbnailWidth, $F_UseForOaiSets,
        $F_PointPrecision, $F_PointDecimalDigits, $F_DefaultValue2,
        $ErrorMessage, $F_UpdateMethod, $F_AllowHTML;

    if ($Field->Status() == MetadataSchema::MDFSTAT_FIELDDOESNOTEXIST)
    {
        $ErrorMessage = "ERROR: Field does not exist.";
        return;
    }

    # Set name and type
    $Field->Name($F_FieldName);
    $Field->Type($F_FieldType);

    # Test the required fields.
    if ( ! $Field->IsTempItem() )
    {
        CheckRequiredFields();

        # Be sure that the name was valid:
        if ($Field->Status() != MetadataSchema::MDFSTAT_OK)
        {
            if ($Field->Status() == MetadataSchema::MDFSTAT_DUPLICATENAME)
            {
                $ErrorMessage = "ERROR: Duplicate field name.";
            }
            else if ($Field->Status() == MetadataSchema::MDFSTAT_ILLEGALNAME)
            {
                $ErrorMessage = "ERROR: Illegal field name.";
            }
        }

        # Bail if anything went wrong
        if (isset($ErrorMessage))
            return;

        # percolate DefaultQualifier for tree fields
        if ($F_FieldType == MetadataSchema::MDFTYPE_TREE)
        {
            SetQualifierIdForClassifications();
        }

        # set DefaultQualifier for Controlled Name fields
        if ($F_FieldType == MetadataSchema::MDFTYPE_CONTROLLEDNAME)
        {
            SetQualifierIdForControlledNames();
        }
    }

    else
    {
        # Be sure that the name was valid:
        if ($Field->Status() != MetadataSchema::MDFSTAT_OK)
        {
            if ($Field->Status() == MetadataSchema::MDFSTAT_DUPLICATENAME)
            {
                $ErrorMessage = "ERROR: Duplicate field name.";
            }
            else if ($Field->Status() == MetadataSchema::MDFSTAT_ILLEGALNAME)
            {
                $ErrorMessage = "ERROR: Illegal field name.";
            }
        }

        CheckRequiredFields();

        # Bail if anything went wrong
        if (isset($ErrorMessage))
            return;
    }

    if ($Field->Type() == MetadataSchema::MDFTYPE_POINT)
    {
        if (isset($F_DefaultValue) && isset($F_DefaultValue2))
        {
            $Field->DefaultValue(array("X" => $F_DefaultValue,
                                       "Y" => $F_DefaultValue2));
        }
    }
    else
    {
        $Field->DefaultValue($F_DefaultValue);
    }

    if ( !$Field->IsTempItem() )
    {
        # need to save some values before they are overwritten
        if ($Field->Type() == MetadataSchema::MDFTYPE_IMAGE)
        {
            $DimensionAttributes = array("", "Preview", "Thumbnail");

            foreach ($DimensionAttributes as $Attribute)
            {
                ${"Current".$Attribute."Width"} = $Field->{"Max".$Attribute."Width"}();
                ${"Current".$Attribute."Height"} = $Field->{"Max".$Attribute."Height"}();
                ${"New".$Attribute."Width"} = ${"F_Max".$Attribute."Width"};
                ${"New".$Attribute."Height"} =  ${"F_Max".$Attribute."Height"};
            }
        }
    }

    # set the attributes
    if ($F_DefaultQualifier == "--")
        $F_DefaultQualifier = NULL;

    # Set attributes which are unconditional
    foreach( array("Enabled","Optional","Viewable","UsesQualifiers",
                   "HasItemLevelQualifiers", "DefaultQualifier",
                   "IncludeInKeywordSearch", "IncludeInAdvancedSearch",
                   "IncludeInSortOptions", "UseForOaiSets",
                   "AllowHTML", "ShowQualifiers") as $Attribute )
    {
        eval('$Field->'.$Attribute.'($F_'.$Attribute.');');
    }

    # Set attributes which must be non-empty:
    foreach( array("Description","DateFormat","FlagOnLabel",
                   "FlagOffLabel","DefaultAltText")
             as $Attribute )
    {
        eval('if (!empty($F_'.$Attribute.')) '
             .'$Field->'.$Attribute.'($F_'.$Attribute.');');
    }

    # Set attributes which must be numeric:
    foreach( array("TextFieldSize", "MaxLength","MinValue","MaxValue",
                   "ParagraphRows","ParagraphCols","AllowMultiple",
                   "MaxHeight","MaxWidth","MaxPreviewHeight",
                   "MaxPreviewWidth","MaxThumbnailHeight","MaxThumbnailWidth",
                   "PointPrecision","PointDecimalDigits") as $Attribute )
    {
        eval('if (is_numeric($F_'.$Attribute.')) '
             .'$Field->'.$Attribute.'($F_'.$Attribute.');');
    }

    # Set search weight
    if (is_numeric($F_SearchWeight))
    {
        # -force search weight between 1 and 20
        if ($F_SearchWeight < 1) $F_SearchWeight = 1;
        if ($F_SearchWeight > 20) $F_SearchWeight = 20;
        $Field->SearchWeight($F_SearchWeight);
    }

    if (isset($F_UpdateMethod) &&
        !( $Field->Name() == "Date Of Record Creation" ||
           $Field->Name() == "Date Last Modified"      ||
           $Field->Name() == "Date Of Record Release" ))
    {
        $Field->UpdateMethod($F_UpdateMethod);
    }

    if ( !$Field->IsTempItem() )
    {
        # tree privilege settings
        if (isset($_POST["F_TreeBrowsingPrivilege"]))
            {  $Field->TreeBrowsingPrivilege($_POST["F_TreeBrowsingPrivilege"]);  }

        # image privilege settings
        if (isset($_POST["F_ImagePreviewPrivilege"]))
            {  $Field->ImagePreviewPrivilege($_POST["F_ImagePreviewPrivilege"]);  }

        # save privilege settings
        if (isset($_POST["F_ViewPriv"]))
            {  $Field->ViewingPrivilege($_POST["F_ViewPriv"]);  }
        if (isset($_POST["F_AuthorPriv"]))
            {  $Field->AuthoringPrivilege($_POST["F_AuthorPriv"]);  }
        if (isset($_POST["F_EditPriv"]))
            {  $Field->EditingPrivilege($_POST["F_EditPriv"]);  }

        # trigger resize task if max width/height values change
        if ($Field->Type() == MetadataSchema::MDFTYPE_IMAGE)
        {
            $DimensionAttributes = array("", "Preview", "Thumbnail");

            foreach ($DimensionAttributes as $Attribute)
            {
                if (${"Current".$Attribute."Width"} != ${"New".$Attribute."Width"}
                    || ${"Current".$Attribute."Height"} != ${"New".$Attribute."Height"})
                {
                    ResizeImages($Field);
                    break;
                }
            }
        }
    }
}

function ResizeImages(MetadataField $Field)
{
    global $AF;

    # don't work with invalid fields or fields that aren't image fields
    if ($Field->Status() != MetadataSchema::MDFSTAT_OK
        || $Field->Type() != MetadataSchema::MDFTYPE_IMAGE)
    {
        return;
    }

    $Database = new Database();
    $FieldId = $Field->Id();
    $DBFieldName = $Field->DBFieldName();
    $MaxWidth = intval($Field->MaxWidth());
    $MaxHeight = intval($Field->MaxHeight());
    $MaxPreviewWidth = intval($Field->MaxPreviewWidth());
    $MaxPreviewHeight = intval($Field->MaxPreviewHeight());
    $MaxThumbnailWidth = intval($Field->MaxThumbnailWidth());
    $MaxThumbnailHeight = intval($Field->MaxThumbnailHeight());

    $Database->Query("
        SELECT I.*
        FROM Images I, Resources R
        WHERE R.".$DBFieldName." IS NOT NULL
        AND I.ImageId = R.".$DBFieldName);

    while (FALSE !== ($Data = $Database->FetchRow()))
    {
        $Image = new SPTImage($Data['ImageId']);

        # skip invalid images
        if ($Image->Status() != AI_OKAY)
        {
            continue;
        }

        $AF->QueueUniqueTask(
            array($Image, "Resize"),
            array($MaxWidth, $MaxHeight,
                  $MaxPreviewWidth, $MaxPreviewHeight,
                  $MaxThumbnailWidth, $MaxThumbnailHeight),
            ApplicationFramework::PRIORITY_BACKGROUND,
            "Resize an image and its preview and thumbnail images after a change
            to its associated metadata field.");
    }
}

# add new field
function AddNewField()
{
    global $Field, $F_FieldId, $ErrorMessage;

    # Dump the data into a temp field
    SaveFormData();

    if (isset($ErrorMessage))
    {
        return;
    }

    # convert the field from temp to real
    $Field->IsTempItem(FALSE);
    $F_FieldId = $Field->Id();

    # Save the real field into the DB
    SaveFormData();
}

# delete a field
function DeleteField()
{
    global $F_FieldId, $Schema, $SysConfig;

    # must re-assign browsing field id if that's what is being deleted
    if ($SysConfig->BrowsingFieldId() == $F_FieldId)
    {
        $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_TREE);
        foreach ($Fields as $Field)
        {
            if ($Field->Id() != $F_FieldId)
            {
                $SysConfig->BrowsingFieldId($Field->Id());
                break;
            }
        }
    }

    # drop the field
    $Field = $Schema->DropField($F_FieldId);

    # remove from OAIFieldMappings too
    $DB = new SPTDatabase();
    $DB->Query("Delete from OAIFieldMappings where SPTFieldId=".$F_FieldId);
}

# function to set DefaultQualifier at all levels in a tree
# if not already set to some other value
function SetQualifierIdForClassifications()
{
    global $Field;

    $F_UsesQualifiers = $_POST["F_UsesQualifiers"];
    $F_HasItemLevelQualifiers = $_POST["F_HasItemLevelQualifiers"];
    $F_DefaultQualifier = $_POST["F_DefaultQualifier"];

    if ($F_UsesQualifiers && $F_DefaultQualifier)
    {
        $ClassFactory = new ClassificationFactory();
        $ClassIds = $ClassFactory->GetItemIds("FieldId = ".$Field->Id());
        foreach ($ClassIds as $Id)
        {
            $Class = new Classification($Id);
            $OldQualifierId = $Class->QualifierId();

            # Check to see if OQId is null, because passing NULL to
            # the Qualifier() constructor will generate a new blank one.
            if (!is_null($OldQualifierId))
            {
                $Qualifier = new Qualifier($OldQualifierId);
            }

            # check if qualifier already assigned and is legit
            if (is_null($OldQualifierId) || $OldQualifierId == 0 ||
                (isset($Qualifier) && is_null($Qualifier->Name())))
            {
                    $Class->QualifierId($F_DefaultQualifier);
            }
        }
    }
}

# function to set DefaultQualifier for a ControlledName field
# if not already set to some other value
function SetQualifierIdForControlledNames()
{
    global $Field;

    $F_UsesQualifiers = $_POST["F_UsesQualifiers"];
    $F_HasItemLevelQualifiers = $_POST["F_HasItemLevelQualifiers"];
    $F_DefaultQualifier = $_POST["F_DefaultQualifier"];

    if ($F_UsesQualifiers && $F_DefaultQualifier)
    {
        $CNFactory = new ControlledNameFactory();
        $CNIds = $CNFactory->GetItemIds("FieldId = ".$Field->Id());
        foreach ($CNIds as $Id)
        {
            $CN = new ControlledName($Id);

            $OldQualifierId = $CN->QualifierId();

            # Check to see if OQId is null, because passing NULL to
            # the Qualifier() constructor will generate a new blank one.
            if (!is_null($OldQualifierId))
            {
                $Qualifier = new Qualifier($OldQualifierId);
            }

            # check if qualifier already assigned and is legit
            if (is_null($OldQualifierId) || $OldQualifierId == 0 ||
                (isset($Qualifier) && is_null($Qualifier->Name())))
            {
                $CN->QualifierId($F_DefaultQualifier);
            }
        }
    }
}

function CheckRequiredFields()
{
    global $ErrorMessage, $Field, $F_FieldType, $F_FieldName, $F_Enabled,
        $F_Optional, $F_Viewable, $F_DefaultValue,$F_UsesQualifiers,
        $F_HasItemLevelQualifiers, $F_DefaultQualifier,
        $F_IncludeInKeywordSearch, $F_IncludeInAdvancedSearch,
        $F_SearchWeight, $F_TextFieldSize, $F_MaxLength, $F_MinValue,
        $F_MaxValue, $F_DateFormat, $F_ParagraphRows, $F_ParagraphCols,
        $F_FlagOnLabel, $F_FlagOffLabel, $F_AllowMultiple, $F_Description,
        $F_DefaultAltText, $F_MaxHeight, $F_MaxWidth, $F_MaxPreviewHeight,
        $F_MaxPreviewWidth, $F_MaxThumbnailHeight, $F_MaxThumbnailWidth,
        $F_PointPrecision, $F_PointDecimalDigits;

    if (empty($F_FieldName))
    {
        $ErrorMessage = "ERROR: Missing required Field Name Field.";
    }
    if (empty($F_Description))
    {
        $ErrorMessage = "ERROR: Missing required Definition Field.";
    }

    switch($F_FieldType)
    {
        case MetadataSchema::MDFTYPE_TEXT:
        case MetadataSchema::MDFTYPE_URL:
            if (empty($F_TextFieldSize))
            {
                $ErrorMessage = "ERROR: Missing required Text Field Size Field.";
            }
            if (empty($F_MaxLength))
            {
                $ErrorMessage = "ERROR: Missing required Max Length Field.";
            }
            break;

        case MetadataSchema::MDFTYPE_POINT:
            if (empty($F_PointPrecision))
            {
                $ErrorMessage = "ERROR: Missing required field Point Precision.";
            }
            if (empty($F_PointDecimalDigits))
            {
                $ErrorMessage = "ERROR: Missing required field Point Decimal Digits.";
            }
            break;

        case MetadataSchema::MDFTYPE_PARAGRAPH:
            if (empty($F_ParagraphRows))
            {
                $ErrorMessage = "ERROR: Missing required Paragraph Rows Field.";
            }
            if (empty($F_ParagraphCols))
            {
                $ErrorMessage = "ERROR: Missing required Paragraph Cols Field.";
            }
            break;

        case MetadataSchema::MDFTYPE_FLAG:
            if (empty($F_FlagOnLabel))
            {
                $ErrorMessage = "ERROR: Missing required Flag On Label Field.";
            }
            if (empty($F_FlagOffLabel))
            {
                $ErrorMessage = "ERROR: Missing required Flag Off Label Field.";
            }
            break;

        case MetadataSchema::MDFTYPE_IMAGE:
            if (empty($F_DefaultAltText))
            {
                $ErrorMessage = "ERROR: Missing required Default Alt Text Field.";
            }
            break;

        case MetadataSchema::MDFTYPE_POINT:
            if (empty($F_PointPrecision))
            {
                $ErrorMessage = "ERROR: Missing required Point Precision FIeld.";
            }
            if (empty($F_PointDecimalDigits))
            {
                $ErrorMessage = "ERROR: Missing required Point Decimal Digits Field.";
            }
            break;
    }
}

# remove Qualifier assocation for this field
function RemoveQualifierAssociation()
{
    global $F_FieldId, $Schema;

    # Get the field
    $Field = $Schema->GetField($F_FieldId);

    $F_AllowedQualifiers = (isset($_POST["F_AllowedQualifiers"]))
        ? $_POST["F_AllowedQualifiers"] : NULL;
    if (!is_null($F_AllowedQualifiers) && $F_AllowedQualifiers != "--")
        $Field->UnassociateWithQualifier($F_AllowedQualifiers);
}

# add Qualifier assocation for this field
function AddQualifierAssociation()
{
    global $F_FieldId, $Schema;

    # Get the field
    $Field = $Schema->GetField($F_FieldId);

    $F_AvailableQualifiers = $_POST["F_AvailableQualifiers"];
    if (isset($F_AvailableQualifiers) && $F_AvailableQualifiers != "--")
        $Field->AssociateWithQualifier($F_AvailableQualifiers);

}

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

# non-standard global variables
global $ErrorMessage, $F_AllowMultiple, $F_DateFormat, $F_DefaultAltText,
    $F_DefaultQualifier, $F_DefaultValue, $F_DefaultValue2, $F_Description,
    $F_Enabled, $F_FieldId, $F_FieldName, $F_FieldType, $F_FlagOffLabel,
    $F_FlagOnLabel, $F_HasItemLevelQualifiers, $F_IncludeInAdvancedSearch,
    $F_IncludeInSortOptions, $F_IncludeInKeywordSearch, $F_MaxHeight,
    $F_MaxLength, $F_MaxPreviewHeight, $F_MaxPreviewWidth,
    $F_MaxThumbnailHeight,$F_MaxThumbnailWidth, $F_MaxValue, $F_MaxWidth,
    $F_MinValue, $F_Optional, $F_ParagraphCols, $F_ParagraphRows,
    $F_SearchWeight, $F_TextFieldSize, $F_UseForOaiSets, $F_UsesQualifiers,
    $F_Viewable, $Field, $Schema, $F_AllowHTML, $F_ShowQualifiers;

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

$Schema = new MetadataSchema();
$F_FieldId = $Schema->GetCurrentEditedItemId();

# get the field
$Field = $Schema->GetField($F_FieldId);

# Pull set vars from $_POST
foreach ( array("FieldName", "FieldType", "Enabled","Optional",
                "Viewable", "DefaultValue","DefaultValue2","UsesQualifiers",
                "HasItemLevelQualifiers","DefaultQualifier",
                "IncludeInKeywordSearch","IncludeInAdvancedSearch",
                "IncludeInSortOptions", "SearchWeight",
                "TextFieldSize","MaxLength","MinValue",
                "MaxValue","DateFormat","ParagraphRows","ParagraphCols",
                "FlagOnLabel","FlagOffLabel","AllowMultiple",
                "Description","DefaultAltText","MaxHeight","MaxWidth",
                "MaxPreviewHeight","MaxPreviewWidth","MaxThumbnailHeight",
                "MaxThumbnailWidth","UseForOaiSets","AllowHTML",
                "ShowQualifiers") as $Var )
{
    eval('$F_'.$Var.'=isset($_POST["F_'.$Var.'"]) ? '
         .'$_POST["F_'.$Var.'"] : NULL;');
}

if ($_POST["Submit"] == "Add New Field")
{
    AddNewField();
    if (isset($ErrorMessage))
    {
        $AF->SetJumpToPage("index.php?P=DBAddField&amp;"
                           ."ErrorMessage=".urlencode($ErrorMessage));
    }
    else
    {
        $AF->SetJumpToPage("index.php?P=DBConfirmAddField&amp;"
                           ."F_FieldName=".urlencode($F_FieldName));
        $Schema->ClearCurrentEditedItemId();
    }
}
else if ($_POST["Submit"] == "Update Field")
{
    SaveFormData();
    if (isset($ErrorMessage))
    {
        $AF->SetJumpToPage("index.php?P=DBAddField&amp;"
                           ."ErrorMessage=".urlencode($ErrorMessage));
    }
    else
    {
        $AF->SetJumpToPage("DBEditor");
        $Schema->ClearCurrentEditedItemId();
    }
}
else if ($_POST["Submit"] == "Populate Field...")
{
    SaveFormData();
    $AF->SetJumpToPage("PopulateField&ID=".$Field->Id());
}
else if ($_POST["Submit"] == "Add Another Field")
{
    $AF->SetJumpToPage("DBAddField");
    $Schema->ClearCurrentEditedItemId();
}
else if ($_POST["Submit"] == "Edit Fields")
{
    $AF->SetJumpToPage("DBEditor");
    $Schema->ClearCurrentEditedItemId();
}
else if (substr($_POST["Submit"], 0, 6) == "Delete")
{
    if (isset($_POST["OkayToDelete"]))
    {
        DeleteField();
        $AF->SetJumpToPage("DBEditor");
        $Schema->ClearCurrentEditedItemId();
    }
    else
    {
        $AF->SetJumpToPage("index.php?P=DBConfirmDeleteField&amp;"
                           ."F_FieldName=".urlencode($F_FieldName)."&amp;"
                           ."F_FieldId=".urlencode($F_FieldId));
    }
}
else if ($_POST["Submit"] == "Cancel")
{
    # delete temporary field and clear current edit id
    if (isset($F_FieldId))
    {
        $Field = $Schema->GetField($F_FieldId);
        if ($Field->IsTempItem())
            DeleteField();
    }
    $Schema->ClearCurrentEditedItemId();
    $AF->SetJumpToPage("DBEditor");
}
else if ($_POST["Submit"] == "&#8595; Remove" || $_POST["Submit"] == "↓ Remove")
{
    SaveFormData();
    RemoveQualifierAssociation();
    $AF->SetJumpToPage("index.php?P=DBAddField");
}
else if ($_POST["Submit"] == "&#8593; Add" || $_POST["Submit"] == "↑ Add")
{
    SaveFormData();
    AddQualifierAssociation();
    $AF->SetJumpToPage("index.php?P=DBAddField");
}
else if ($_POST["Submit"] == "Populate")
{
    $F_PopulateTree = $_POST["F_PopulateTree"];
    if (!empty($F_PopulateTree))
    {
        $Field = $Schema->GetField($F_FieldId);
        if ($Field->Type() == MetadataSchema::MDFTYPE_TREE)
        {
            $Status = PopulateTree($Field, $F_PopulateTree);
            if ($Status == FALSE)
            {
                $ErrorMessage = "WARNING: Cannot populate tree.".
                "\"$F_PopulateTree\" not found";
            }
            else
            {
                $ErrorMessage =
                    "Field populated successfully.";
            }
        }
    }
    else
    {
        $ErrorMessage = "You must select a taxonomy.";
    }
    $Session->PassVariable("ErrorMessage", $ErrorMessage);

    $AF->SetJumpToPage("DBPopulateTree");
}
else if (isset($_POST["Submit"]))
{
    $F_FieldType = $_POST["Submit"];
    SaveFormData();

    $AF->SetJumpToPage("index.php?P=DBAddField&amp;"
                       ."F_FieldType=".$F_FieldType);
}
else
{
    if (isset($ErrorMessage))
    {
        $AF->SetJumpToPage("index.php?P=DBAddField&amp;"
                           ."ErrorMessage=".urlencode($ErrorMessage));
    }
    else
    {
        $AF->SetJumpToPage("index.php?P=DBAddField");
    }
}
