<?php
/**
 * This file contains the {@link Signature} class.
 * @copyright (c) 2015, Scriptel Corporation.
 */
namespace com\scriptel;

/**
 * This class represents a parsed signature from a Scriptel ScripTouch EasyScript
 * device.
 */
class Signature {
    /**
     * The captured protocol version. At present A, B, C, D and E exist.
     * @var string
     */
    private $protocolVersion;
    /**
     * The model of the device that captured the signature.
     * @var string
     */
    private $model;
    /**
     * The currently running version of the firmware on the device that captured the signature.
     * @var string
     */
    private $version;
    /**
     * An array of coordinate arrays containing the pen strokes parsed from the signature stream.
     * @var Coordinate[][]
     */
    private $strokes;
    /**
     * The current used signature protocol (STNSignatureProtocol).
     * @var SignatureProtocol
     */
    private $signatureProtocol;
    /**
     * The width of the device's display in pixels.
     * @var integer 
     */
    private $width;
    /**
     * The height of the device's display in pixels.
     * @var integer 
     */
    private $height;
    
    /**
     * Constructor, creates a new instance of Signature class.
     * @param SignatureMetaData $signatureMetaData All of the non-signature related data.
     * @param Coordinate[][] $strokes List of strokes containing coordinates.
     */
    public function __construct(SignatureMetaData $signatureMetaData, $strokes) {
        $this->protocolVersion = $signatureMetaData->getProtocolVersion();
        $this->model = $signatureMetaData->getModel();
        $this->version = $signatureMetaData->getVersion();
        $this->strokes = $strokes;
        $this->signatureProtocol = new STNSignatureProtocol;
        $this->width = $this->signatureProtocol->getWidth();
        $this->height = $this->signatureProtocol->getHeight();
    }
    /**
     * Gets the protocol version used to generate the EasyScript string.
     * @return string Protocol version.
     */
    function getProtocolVersion() {
        return $this->protocolVersion;
    }
    /**
     * The model number of the device used to create the string.
     * @return string Model number.
     */
    function getModel() {
        return $this->model;
    }
    /**
     * The firmware version of the device used to create the string.
     * @return string Firmware version.
     */
    function getVersion() {
        return $this->version;
    }
    /**
     * List of strokes containing lists of points that make up the encoded
     * signature.
     * @return Coordinate[][] List of strokes.
     */
    function getStrokes() {
        return $this->strokes;
    }
    /**
     * Gets the metadata associated with this signature.
     * @return SignatureMetaData Metadata associated with this signature.
     */
    function getSignatureMetaData() {
        return new SignatureMetaData($this->getProtocolVersion(), $this->getModel(), $this->getVersion());
    }

    /**
     * This method gets the bounding box surrounding the signature
     * stored within this object.
     * @return BoundingBox The bounding box surrounding the signature.
     */
    public function getBounds() {
        $retr = new BoundingBox();
        for($i=0;$i<count($this->strokes);$i++) {
            for($j=0;$j<count($this->strokes[$i]);$j++) {
                $p = $this->strokes[$i][$j];

                $retr->setX1(($p->getX()<$retr->getX1())?$p->getX():$retr->getX1());
                $retr->setX2(($p->getX()>$retr->getX2())?$p->getX():$retr->getX2());
                $retr->setY1(($p->getY()<$retr->getY1())?$p->getY():$retr->getY1());
                $retr->setY2(($p->getY()>$retr->getY2())?$p->getY():$retr->getY2());
            }
        }
        $retr->setWidth($retr->getX2()-$retr->getX1());
        $retr->setHeight($retr->getY2()-$retr->getY1());
        return $retr;
    }
    /**
     * This method crops the signature to fit within the smallest space possible.
     */
    public function crop() {
        $bounds = $this->getBounds();
        for($i=0;$i<count($this->strokes);$i++) {
            for($j=0;$j<count($this->strokes[$i]);$j++) {
                $this->strokes[$i][$j]->setX($this->strokes[$i][$j]->getX()-$bounds->getX1());
                $this->strokes[$i][$j]->setY($this->strokes[$i][$j]->getY()-$bounds->getY1());
            }
        }
        $this->setWidth(ceil($bounds->getWidth()));
        $this->setHeight(ceil($bounds->getHeight()));
    }
    /**
     * This method renders the signature stored in this object as a PNG using GD.
     * @param int $scale Scale Scale by which to scale the signature up or down in size.
     * @param int $lineThickness The thickness of the resulting line. This is scaled up and down with scale.
     * @param int[] $foreColor A four index array containing the color of the foreground color in red, green, blue, alpha format.
     * @param int[] $backColor A four index array containing the coolor of the background color in red, green, blue, alpha format.
     * @param string $fileName The file name to save this image as, if omitted it will be printed.
     */
    public function getImagePng($scale=1,$lineThickness=1,$foreColor=array(0,0,0,0),$backColor=array(0xFF,0xFF,0xFF,127),$fileName=false) {
        $bounds = $this->getBounds();

        $width = $this->getWidth()*$scale;
        $height = $this->getHeight()*$scale;

        $img = imagecreatetruecolor($width,$height);
        $foreground = imagecolorallocatealpha($img,$foreColor[0],$foreColor[1],$foreColor[2],$foreColor[3]);
        $background = imagecolorallocatealpha($img,$backColor[0],$backColor[1],$backColor[2],$backColor[3]);

        imagealphablending($img, false);
        imagesavealpha($img,true);
        imagesetthickness($img,$lineThickness*$scale);

        if(function_exists("imageantialias")) {
            imageantialias ($img,true);
        }

        imagefill($img,0,0,$background);

        for($i=0;$i<count($this->strokes);$i++) {
            for($j=1;$j<count($this->strokes[$i]);$j++) {
                $p1 = $this->strokes[$i][$j-1];
                $p2 = $this->strokes[$i][$j];

                imageline($img,$p1->getX()*$scale,$p1->getY()*$scale,$p2->getX()*$scale,$p2->getY()*$scale,$foreground);
            }
        }

        if($fileName===false) {
            $fileName=NULL;
        }
        imagepng($img,$fileName,9);
    }
    /**
     * This method should return the width of the signature in pixels.
     * @return integer
     */
    function getWidth() {
        return $this->width;
    }
    /**
     * This method should return the height of the signature in pixels.
     * @return integer 
     */
    function getHeight() {
        return $this->height;
    }

    /**
     * This method sets the width of the signature in pixels.
     * @param int width Width in pixels.
     */
    function setWidth($width) {
        $this->width = $width;
    }

    /**
     * This method sets the height of the signature in pixels.
     * @param int height Height in pixels.
     */
    function setHeight($height) {
        $this->height = $height;
    }
}