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

/**
* Resource Export format implementing Tab Seperated Value (TSV) files.
*/
class REFormatTsv extends Plugin {

    # ---- STANDARD PLUGIN INTERFACE -----------------------------------------

    /**
    * Set plugin attributes.
    */
    function Register()
    {
        $this->Name = "Resource Export Format: TSV";
        $this->Version = "1.0.0";
        $this->Description = "";
        $this->Author = "Internet Scout";
        $this->Url = "http://scout.wisc.edu/cwis/";
        $this->Email = "scout@scout.wisc.edu";
        $this->Requires = array(
            "CWISCore" => "3.0.0",
            "ResourceExporter" => "1.0.0");
        $this->EnabledByDefault = TRUE;
    }

    /**
    * Initialize the plugin.  This is called (if the plugin is enabled) after
    * all plugins have been loaded but before any methods for this plugin
    * (other than Register()) have been called.
    * @return NULL if initialization was successful, otherwise a string containing
    *       an error message indicating why initialization failed.
    */
    function Initialize()
    {
        $ExportedDataTypes = array(
            MetadataSchema::MDFTYPE_TEXT,
            MetadataSchema::MDFTYPE_PARAGRAPH,
            MetadataSchema::MDFTYPE_NUMBER,
            MetadataSchema::MDFTYPE_TIMESTAMP,
            MetadataSchema::MDFTYPE_URL,
            MetadataSchema::MDFTYPE_DATE,
            MetadataSchema::MDFTYPE_FLAG,
            MetadataSchema::MDFTYPE_TREE,
            MetadataSchema::MDFTYPE_CONTROLLEDNAME,
            MetadataSchema::MDFTYPE_OPTION,
            MetadataSchema::MDFTYPE_POINT,
            MetadataSchema::MDFTYPE_USER,
            );
        $GLOBALS["G_PluginManager"]->GetPlugin("ResourceExporter")->
            RegisterFormat("TSV", "tsv", array($this, "Export"), $ExportedDataTypes,
                           array(
                               "UniqueFields" => array(
                                   "Type" => "MetadataField",
                                   "Label" => "Unique Fields",
                                   "Help" => "Field or fields used to uniquely identify "
                                     ."a resource.  If not specificed, defaults to "
                                     ." Title + Description",
                                   "FieldTypes" => MetadataSchema::MDFTYPE_TEXT |
                                                   MetadataSchema::MDFTYPE_PARAGRAPH |
                                                   MetadataSchema::MDFTYPE_URL,
                                   "AllowMultiple" => TRUE)));

        return NULL;
    }

    # ---- HOOKED METHODS ----------------------------------------------------

    /**
    * HOOKED METHOD:
    */


    # ---- CALLABLE METHODS --------------------------------------------------

    /**
    * Export resource metadata to TSV format.
    * @param array $ResourceIds Array of Resource IDs.
    * @param array $FieldIds Array of IDs of metadata fields to export.
    *       (NULL to export all enabled fields)
    * @param string $FileName Name of file to export to with leading path.
    * @param array $ParamSettings Settings for any export parameters, with
    *       parameter names for the array index and parameter settings for
    *       the array values.
    * @return int Number of resources exported, or NULL if export failed.
    */
    function Export($ResourceIds, $FieldIds, $FileName, $ParamSettings)
    {
        # create file and open a filehandle
        touch($FileName);
        $fp = fopen($FileName, "w");

        # extract schema information
        $Schema = new MetadataSchema();
        $Fields = $Schema->GetFields(NULL, MetadataSchema::MDFORDER_EDITING);

        # extract settings about unique fields, defaulting to Title + Description
        #  if nothing was selected
        $UniqueFields = array();
        if (isset($ParamSettings["UniqueFields"]))
        {
            foreach ($ParamSettings["UniqueFields"] as $FieldId)
            {
                $ThisField = new MetadataField($FieldId);
                $UniqueFields[ $ThisField->Name() ] = 1;
            }
        }
        else
        {
            $UniqueFields ["Title"] = 1;
            $UniqueFields ["Description"] = 1;
        }

        # output a header line giving the field names
        $OutputData = array();
        foreach ($Fields as $Field)
        {
            if ($Field->Enabled()
                && (($FieldIds == NULL)
                    || in_array($Field->Id(), $FieldIds)))
                $OutputData []= $Field->Name();
        }
        fwrite( $fp, implode("\t", $OutputData)."\n" );

        # foreach resource
        $ExportedResourceCount = 0;
        foreach ($ResourceIds as $ResourceId)
        {
            # load resource
            $Resource = new Resource($ResourceId);

            # create an array representing the values we'll need to output,
            # with field names as keys that point to arrays of values
            $OutputData = array();

            # foreach metadata field
            foreach ($Fields as $Field)
            {
                # if field is enabled and was requested for export
                if ($Field->Enabled()
                    && (($FieldIds == NULL)
                        || in_array($Field->Id(), $FieldIds)))
                {
                    # start off assuming no content for this field
                    $OutputValue = "";

                    # pull out the value(s) in the field
                    $Value = $Resource->Get($Field, TRUE);
                    if ((is_array($Value) && count($Value))
                        || (!is_array($Value) && ($Value !== NULL)))
                    {
                        # handle output of field based on field type
                        switch ($Field->Type())
                        {
                            case MetadataSchema::MDFTYPE_TEXT:
                            case MetadataSchema::MDFTYPE_PARAGRAPH:
                            case MetadataSchema::MDFTYPE_NUMBER:
                            case MetadataSchema::MDFTYPE_TIMESTAMP:
                            case MetadataSchema::MDFTYPE_URL:
                                if (strlen($Value))
                                    $OutputValue = str_replace( array("\r","\n","\t"), " ", $Value);
                                break;

                            case MetadataSchema::MDFTYPE_DATE:
                                if (strlen($Value->Formatted()))
                                    $OutputValue= $Value->Formatted();
                                break;

                            case MetadataSchema::MDFTYPE_FLAG:
                                $OutputValue =  ($Value ? "TRUE" : "FALSE");
                                break;

                            case MetadataSchema::MDFTYPE_TREE:
                            case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
                            case MetadataSchema::MDFTYPE_OPTION:
                                $OutputValue = array();
                                foreach ($Value as $Item)
                                {
                                    $OutputValue []= $Item->Name();
                                }
                                break;

                            case MetadataSchema::MDFTYPE_POINT:
                                $OutputValue = $Value["X"].",".$Value["Y"] ;
                                break;

                            case MetadataSchema::MDFTYPE_USER:
                                if (strlen($Value->Get("UserName")))
                                    $OutputValue = array( $Value->Get("UserName") );
                                break;

                            default:
                                throw new Exception(
                                    "Export of unsupported metadata field type ("
                                    .MetadataSchema::GetConstantName(
                                        $Field->Type(), "MDFTYPE")
                                    .") requested.");
                                break;
                        }
                    }

                    # add the value(s) to our OutputData
                    if (is_array($OutputValue))
                        $OutputData[ $Field->Name() ] = $OutputValue;
                    else
                        $OutputData[ $Field->Name() ] []= $OutputValue;

                }
            }

            # iterate over our OutputData, generating as many rows as we need in the output file
            # in order to encode all the multi-value fields
            do
            {
                $Done = TRUE;
                $Row = array();

                # iterate over the fields adding them to the output for this row
                foreach ($OutputData as $FieldName => &$FieldContent)
                {
                    # repeat key fields in every row
                    if ( isset($UniqueFields[$FieldName]) )
                    {
                        $Row[] = $FieldContent[0];
                    }
                    else
                    {
                        # for non-key fields, shift a value off of the array
                        $var = array_shift($FieldContent);

                        if ( !is_null($var) )
                        {
                            # if there was a value, stick it into our output row
                            $Row []= $var;

                            # and if there are more values left, note that
                            # we're not finished
                            if (count($FieldContent)>0)
                                $Done = FALSE;
                        }
                        else
                        {
                            # otherwise (when there is no value), then put a
                            # blank placeholder in our output row for this field
                            $Row []= "";
                        }
                    }
                }
                # output the row we've constructed as a TSV
                fwrite( $fp, implode("\t", $Row)."\n" );
            } while (!$Done);

            $ExportedResourceCount++;
        }

        fclose($fp);

        # return number of exported resources to caller
        return $ExportedResourceCount;
    }

    # ---- PRIVATE INTERFACE -------------------------------------------------
}
