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

/**
 * Base class for ASN.1 objects.
 *
 * @package asn1
 */
abstract class ASN1Object implements ASN1DEREncodable, ASN1DERDecodable {

    protected $tagClass;
    protected $tagType;
    protected $tagValue;

    /**
     * Appends bytes to the given byte stream.
     *
     * @param  arrayref &$stream stream to append bytes to
     * @param  array $bytes the bytes to append
     * @return void
     */
    protected function append(&$stream, $bytes) {

        if (!is_array($bytes)) {
            $bytes = array($bytes);
        }

        foreach ($bytes as $b) {
            array_push($stream, $b);
        }
    }

    /**
     * Prepends bytes to the given byte stream.
     *
     * @param  arrayref &$stream stream to prepend bytes to
     * @param  array $bytes the bytes to prepend
     * @return void
     */
    protected function prepend(&$stream, $bytes) {

        if (!is_array($bytes)) {
            $bytes = array($bytes);
        }

        for ($i = count($bytes) - 1; $i >= 0; $i--) {
            array_unshift($stream, $bytes[$i]);
        }

    }

    /**
     * Reads a single byte from the given stream.
     *
     * @param  arrayref &$stream the stream to read from
     * @return int single byte
     */
    protected function readByte(&$stream) {

        $bytes = $this->readBytes($stream, 1);

        return array_shift($bytes);

    }

    /**
     * Reads multiple bytes from the given stream.
     *
     * @throws GTException
     * @param  arrayref &$stream the stream to read from
     * @param  int $limit number of bytes to read
     * @return array byte array containing the bytes read from stream
     */
    protected function readBytes(&$stream, $limit) {

        if (!is_array($stream)) {
            throw new GTException("parameter stream must be an array of bytes");
        }

        if (count($stream) < $limit) {
            throw new GTException("not enough bytes, tried to read {$limit}, but only " . count($stream) . " remaining");
        }

        $bytes = array();

        for ($i = 0; $i < $limit; $i++) {
            array_push($bytes, array_shift($stream));

        }

        return $bytes;
    }


    /**
     * Sets the tag class for this ASN1 Object.
     *
     * Valid values are:
     * <pre>
     * ASN1_TAG_CONEXT
     * ASN1_TAG_PRIVATE
     * ASN1_TAG_UNIVERSAL
     * ASN1_TAG_APPLICATION
     * </pre>
     *
     * @param  $tagClass the tag class to set
     * @return void
     */
    public function setTagClass($tagClass) {
        $this->tagClass = $tagClass;
    }

    /**
     * Gets the tag class for this ASN1 Object.
     *
     * @return string the tag class
     */
    public function getTagClass() {
        return $this->tagClass;
    }

    /**
     * Sets the tag type for this ASN1 Object.
     *
     * Valid values are:
     * <pre>
     * ASN1_TAG_PRIMITIVE
     * ASN1_TAG_CONSTRUCTED
     * </pre>
     *
     * @param  $tagType the tag type to set
     * @return void
     */
    public function setTagType($tagType) {
        $this->tagType = $tagType;
    }

    /**
     * Gets the tag value for this ASN1 Object.
     *
     * @return string the tag type
     */
    public function getTagType() {
        return $this->tagType;
    }

    /**
     * Sets the tag value for this ASN1 Object.
     *
     * @param  int $tagValue the tag value
     * @return void
     */
    public function setTagValue($tagValue) {
        $this->tagValue = $tagValue;
    }

    /**
     * Gets the tag value for this ASN1 Object.
     *
     * @return int the tag value
     */
    public function getTagValue() {
        return $this->tagValue;
    }

}

?>
