<?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 x509
 */

/**
 * X.509 Extension implementation.
 *
 * <pre>
 * Extension ::= SEQUENCE {
 *   extnid                  OBJECT IDENTIFIER,
 *   critical                BOOLEAN DEFAULT FALSE,
 *   extnValue               OCTETSTRING
 * }
 * </pre>
 *
 * @package asn1
 * @subpackage x509
 */
class X509Extension implements ASN1DEREncodable {

    private $id;
    private $critical;
    private $value;

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

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

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

        $size = $object->getObjectCount();

        if ($size < 1) {
            throw new GTException("Invalid sequence size: {$size}");
        }

        $id = $object->getObjectAt(0);

        if (!$id instanceof ASN1ObjectId) {
            throw new GTException("Expecting an ASN1ObjectId");
        }

        $this->id = $id->getValue();

        if ($size == 2) {

            $value = $object->getObjectAt(1);

            if (!$value instanceof ASN1OctetString) {
                throw new GTException("Expecting an ASN1OctetString");
            }

            $this->value = $value->getValue();
            $this->critical = false;

        } else if ($size == 3) {

            $critical = $object->getObjectAt(1);

            if (!$critical instanceof ASN1Boolean) {
                throw new GTException("Expecting an ASN1Boolean");
            }

            $this->critical = $critical->getValue();

            $value = $object->getObjectAt(2);

            if (!$value instanceof ASN1OctetString) {
                throw new GTException("Expecting an ASN1OctetString");
            }

            $this->value = $value->getValue();

        } else {
            throw new GTException("Invalid sequence size: {$size}");

        }

    }

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

        $sequence = new ASN1Sequence();

        $sequence->add(new ASN1ObjectId($this->id));

        if ($this->isCritical() === true) {
            $sequence->add(new ASN1Boolean(true));
        }

        $sequence->add(new ASN1OctetString($this->value));

        return $sequence->encodeDER();
    }

    /**
     * Gets the id.
     *
     * @return string oid
     */
    public function getId() {
        return $this->id;
    }

    /**
     * Sets the id.
     *
     * @param  string $id oid
     * @return void
     */
    public function setId($id) {
        $this->id = $id;
    }

    /**
     * Checks if this extension is critical.
     *
     * @return bool true if this extension is critical
     */
    public function isCritical() {
        return $this->critical;
    }

    /**
     * Sets the critical status of this extension.
     *
     * @param  bool $critical true if this extension is critical
     * @return void
     */
    public function setCritical($critical) {
        $this->critical = $critical;
    }

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

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

?>
