<?php
/*
 * Copyright 2008-2010 GuardTime AS
 *
 * This file is part of the GuardTime PHP SDK.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @package asn1
 * @subpackage gt
 */

/**
 * GT TimeSignature implementation.
 *
 * <pre>
 * TimeSignature ::= SEQUENCE {
 *    location        OCTET STRING,
 *    history         OCTET STRING,
 *    publishedData   PublishedData,
 *    pkSignature     [0] IMPLICIT SignatureInfo OPTIONAL,
 *    pubReference    [1] IMPLICIT SET OF OCTET STRING OPTIONAL
 * }
 * </pre>
 *
 * @package asn1
 * @subpackage gt
 */
class GTTimeSignature implements ASN1DEREncodable {

    /**
     * Object identifier of the GuardTime TimeSignature algorithm.
     */
    const OID = "1.3.6.1.4.1.27868.4.1";

    private $location;
    private $history;
    private $publishedData;
    private $pkSignature;
    private $pubReference;

    /**
     * Constructs a new instance of GTTimeSignature.
     */
    public function __construct() {
    }

    /**
     * Decodes the given ASN1Sequence as GTTimeSignature.
     *
     * @throws GTException
     * @param  ASN1Sequence $object GTTImeSignature encoded as ASN1Sequence
     * @return void
     */
    public function decode($object) {

        if (is_array($object)) {
            $object = ASN1DER::decode($object);
        }

        if (!$object instanceof ASN1Sequence) {
            throw new GTException("Expecting an ASN1Sequence");
        }

        $size = $object->getObjectCount();

        if ($size < 3 || $size > 5) {
            throw new GTException("Invalid sequence size: {$size}");
        }

        $location = $object->getObjectAt(0);
        $history = $object->getObjectAt(1);

        if (!$location instanceof ASN1OctetString) {
            throw new GTException("Expecting an ASN1OctetString for GTTimeSignature.location");
        }

        if (!$history instanceof ASN1OctetString) {
            throw new GTException("Expecting an ASN1OctetString for GTTimeSignature.history");
        }

        $this->location = $location->getValue();
        $this->history = $history->getValue();

        $publishedData = new GTPublishedData();
        $publishedData->decode($object->getObjectAt(2));

        $this->publishedData = $publishedData;

        for ($i = 3; $i < $object->getObjectCount(); $i++) {

            $tag = $object->getObjectAt($i);

            if (!$tag instanceof ASN1Tag) {
                throw new GTException("Expecting an ASN1Tag");
            }

            switch ($tag->getTagValue()) {

                case 0:
                    //pkSignature
                    $sequence = $tag->getObjectAs(ASN1_TAG_SEQUENCE);

                    $pkSignature = new GTSignatureInfo();
                    $pkSignature->decode($sequence);

                    $this->pkSignature = $pkSignature;

                    break;

                case 1:
                    // pubReference
                    $set = $tag->getObjectAs(ASN1_TAG_SET);

                    $pubReference = array();

                    foreach ($set->getObjects() as $item) {
                        array_push($pubReference, $item->getValue());
                    }

                    $this->pubReference = $pubReference;

                    break;

                default:
                    throw new GTException("Unsupported ASN1Tag: " . $tag->getTagValue());

            }

        }
    }

    /**
     * Encodes this GTTimeSignature using DER.
     *
     * @return array byte array containing the DER encoding of this GTTimeSignature
     *
     */
    public function encodeDER() {

        $sequence = new ASN1Sequence();

        $sequence->add(new ASN1OctetString($this->location));
        $sequence->add(new ASN1OctetString($this->history));
        $sequence->add($this->publishedData);

        if ($this->pkSignature !== null) {

            $tag = new ASN1Tag();
            $tag->setTagValue(0);
            $tag->setExplicit(false);
            $tag->setTagClass(ASN1_TAG_CONTEXT);
            $tag->setTagType(ASN1_TAG_CONSTRUCTED);
            $tag->setObject($this->pkSignature);

            $sequence->add($tag);

        }

        if ($this->pubReference !== null) {

            $set = new ASN1Set();

            foreach ($this->pubReference as $item) {
                $set->add(new ASN1OctetString($item));
            }

            $tag = new ASN1Tag();
            $tag->setTagValue(1);
            $tag->setExplicit(false);
            $tag->setTagClass(ASN1_TAG_CONTEXT);
            $tag->setTagType(ASN1_TAG_CONSTRUCTED);
            $tag->setObject($set);

            $sequence->add($tag);
        }

        return $sequence->encodeDER();

    }

    /**
     * Checks if this time signature is extended.
     *
     * @return bool true if this time signature is extended
     */
    public function isExtended() {
        return $this->pkSignature == null;
    }

    /**
     * Gets the encoded publication references.
     *
     * @return string encoded publication references
     */
    public function getEncodedPublicationReferences() {

        $string = "";
        $string .= "[";

        if (!empty($this->pubReference)) {
            foreach ($this->pubReference as $reference) {
                $string .= GTBase16::encodeWithSpaces($reference);
                $string .= ',';
            }
        }

        $string .= "]";

        return $string;

    }

    /**
     * Gets the location bytes.
     *
     * @return array byte array containing the location bytes
     */
    public function getLocation() {
        return $this->location;
    }

    /**
     * Sets the location bytes.
     *
     * @param  array $location byte array containing the location bytes
     * @return void
     */
    public function setLocation($location) {
        $this->location = $location;
    }

    /**
     * Gets the history bytes.
     *
     * @return array byte array containing the history bytes
     */
    public function getHistory() {
        return $this->history;
    }

    /**
     * Sets the history bytes.
     *
     * @param  array history byte array containing the history bytes
     * @return void
     */
    public function setHistory($history) {
        $this->history = $history;
    }

    /**
     * Gets the published data.
     *
     * @return GTPublishedData published data
     */
    public function getPublishedData() {
        return $this->publishedData;
    }

    /**
     * Sets the published data.
     *
     * @param  GTPublishedData $publishedData published data
     * @return void
     */
    public function setPublishedData($publishedData) {
        $this->publishedData = $publishedData;
    }

    /**
     * Gets the public key signature.
     *
     * @return GTSignatureInfo public key signature
     */
    public function getPkSignature() {
        return $this->pkSignature;
    }

    /**
     * Sets the public key signature.
     *
     * @param  GTSignatureInfo $pkSignature public key signature
     * @return void
     */
    public function setPkSignature($pkSignature) {
        $this->pkSignature = $pkSignature;
    }

    /**
     * Gets the pub reference.
     *
     * @return array pub reference
     */
    public function getPubReference() {
        return $this->pubReference;
    }

    /**
     * Sets the pub reference.
     *
     * @param  array $pubReference pub reference
     * @return void
     */
    public function setPubReference($pubReference) {
        $this->pubReference = $pubReference;
    }

}

?>
