<?php

/**
 * Properties are private by design.
 * You should never edit an object. Just create a new one as you need to remove the old object and add the new one.
 */
class LayoutObject {
    const UNPACK = 'sX/sY/CZ/CFlags/CIndex/CHeading';
    const PACK = 'ssCCCC';

    private $x;
    private $y;
    private $z;

    private $hdng;

    private $index = -1;
    private $type;
    private $typeData = 0; /** object index / circle radius / checkpoint half-width */
    private $colour = 0;

    public static $OBJ_REAL_OBJECT      = 'object';
    public static $OBJ_RESTRICTED       = 'restricted_area';
    public static $OBJ_MARSHALL         = 'marshall';
    public static $OBJ_MARSHALL_LEFT    = 'marshall_left';
    public static $OBJ_MARSHALL_RIGHT   = 'marshall_right';
    public static $OBJ_ROUTE_CHECK      = 'route_check';
    public static $OBJ_START            = 'start';
    public static $OBJ_CHECK_1          = 'check_1';
    public static $OBJ_CHECK_2          = 'check_2';
    public static $OBJ_CHECK_3          = 'check_3';
    public static $OBJ_FINISH            = 'finish';

    /**
     * Constructor.
     * Either pass an 8 Byte data struture provided by insim or in the layout file or all other params as well.
     * @param dataOrX 8 byte data or value for X coordinate
     * @param y Y coordinate
     * @param z Z coordinate
     * @param type one of LayoutObject::$OBJ_... values
     * @param hdng heading in degree or route index
     * @param typeData object index, circle radius or half-width of control point
     * @param colour Colour for chalk and tyre stacks
     */
    public function __construct($dataOrX, $y = null, $z = null, $type = null, $hdng = null, $typeData = null, $colour = null) {
        if ($type != null)
        {
            $this->x = $dataOrX;
            $this->y = $y;
            $this->z = $z;
            $this->type = $type;
            if ($this->type == self::$OBJ_ROUTE_CHECK)
            {
                $this->setRouteIndex($hdng);
            }
            else
            {
                $this->setHeading($hdng);
            }
            $this->typeData = $typeData;
            $this->colour = $colour;
        }
        else {
            $this->initFromBytes($dataOrX);
        }
    }

    public function __toString() {
        $retVal = $this->type;

        if ($this->type == self::$OBJ_REAL_OBJECT)
        {
            $retVal .= ': ' . self::$REV_AXO[$this->typeData];
            if ($this->typeData >= self::$AXO_CHALK_LINE && $this->typeData <= self::$AXO_CHALK_RIGHT3)
            {
                $retVal .= ', col:' . self::$REV_CC[$this->colour];
            }
            else if ($this->typeData >= self::$AXO_TYRE_SINGLE && $this->typeData <= self::$AXO_TYRE_STACK4_BIG)
            {
                $retVal .= ', col:' . self::$REV_TC[$this->colour];
            }
        }
        return $retVal;
    }

    public function pack() {
        $x = $this->rawX();
        $y = $this->rawY();
        $z = $this->z * 4;

        $dat = $this->dataForType();
        $flags = $dat['flags'];
        $index = $dat['index'];
        $heading = $dat['heading'];

        return pack(LayoutObject::PACK, $x, $y, $z, $flags, $index, $heading);
    }

    public function rawX()
    {
        return round($this->x * 16);
    }

    public function rawY()
    {
        return round($this->y * 16);
    }

    public function initFromBytes($data) {
    $obj = unpack(LayoutObject::UNPACK, $data);
        // scale ...
        $this->x = $obj['X'] / 16;
        $this->y = $obj['Y'] / 16;
        $this->z = $obj['Z'] / 4;
        $this->setHeading($obj['Heading'] / 256 * 360);

        $ix = $obj['Index'];
        $this->index = $ix;
        $flg = $obj['Flags'];

        if ($ix >= 192) // either a circle or an unknown object
        {
            if ($ix==254) // it's a marshall circle
            {
                if (($flg & 0x80) != 0) // highest bit set : restricted area
                {
                    // HeadingByte has the same meaning as it does for all objects
                    // Flags byte contains the following data :
                    // bits 0 to 1 :
                    switch ($flg & 0x03) {
                        // 00 = no marshall
                        case 0:
                            $this->type = self::$OBJ_RESTRICTED;
                            break;
                        // 01 = standing marshall
                        case 1:
                            $this->type = self::$OBJ_MARSHALL;
                            break;
                        // 10 = marshall pointing left
                        case 2:
                            $this->type = self::$OBJ_MARSHALL_LEFT;
                            break;
                        // 11 = marshall pointing right
                        case 3:
                            $this->type = self::$OBJ_MARSHALL_RIGHT;
                            break;
                    }
                    // bits 2 to 5 :
                    // circle diameter in metres (shifted left by 2 bits)
                    $this->typeData = ($flg >> 2) & 0x07;
                }
                else // highest bit of flags is not set : route checker
                {
                    $this->type = self::$OBJ_ROUTE_CHECK;
                    // HeadingByte is used not for heading, but the route index
                    // bits 2 to 5 :
                    // circle diameter in metres (shifted left by 2 bits)
                    $this->typeData = ($flg >> 2) & 0x0F;
                    $this->hdng = $obj['Heading'];
                }
            }
            else
            {
                // unknown object - ignore
                $this->type = array($flg, $ix);
            }
        }
        else // could be an actual object or a control object
        {
            if(($flg & 0x80) != 0) // highest bit set : control object
            // bit 6 : never set
            // bit 7 : always set (0x80)
            {
                // bits 2 to 5 :
                // Checkpoint width(half width!) in metres (shifted left by 2 bits)
                $this->typeData = (($flg >> 2) & 0x07);
                // Flags byte contains the following data :
                // bits 0 to 1 :
                switch ($flg & 0x03) {
                    // 00 = Start position (if width = 0) or finish line (if width > 0)
                    case 0:
                        if ($this->typeData == 0) {
                            $this->type = self::$OBJ_START;
                        }
                        else {
                            $this->type = self::$OBJ_FINISH;
                        }
                        break;
                    // 01 = Checkpoint 1
                    case 1:
                        $this->type = self::$OBJ_CHECK_1;
                        break;
                    // 10 = Checkpoint 2
                    case 2:
                        $this->type = self::$OBJ_CHECK_2;
                        break;
                    // 11 = Checkpoint 3
                    case 3:
                        $this->type = self::$OBJ_CHECK_3;
                        break;
                }
            }
            else // highest bit of flags is not set : autocross object
            {
                $this->type = self::$OBJ_REAL_OBJECT;
                // save flag as colour (even if it's just tyres and chalk)
                echo 'flag is:'.$flg;
                $this->colour = $flg;
                $this->typeData = $ix;
            }
        }
    }

    /**
     * Computes the index flag and heading fields for the current object.
     * @return array Array containing the value for 'flags', 'index' and 'heading'
     */
    public function dataForType() {
        $dat = array();

        switch($this->type) {
            case self::$OBJ_RESTRICTED:
                $dat['flags'] = $this->typeData << 2 & 0x3C | 0x80;
                $dat['index'] = 254;
                break;
            case self::$OBJ_MARSHALL:
                $dat['flags'] = $this->typeData << 2 & 0x3C | 0x81;
                $dat['index'] = 254;
                break;
            case self::$OBJ_MARSHALL_LEFT:
                $dat['flags'] = $this->typeData << 2 & 0x3C | 0x82;
                $dat['index'] = 254;
                break;
            case self::$OBJ_MARSHALL_RIGHT:
                $dat['flags'] = $this->typeData << 2 & 0x3C | 0x83;
                $dat['index'] = 254;
                break;
            case self::$OBJ_ROUTE_CHECK:
                $dat['flags'] = $this->typeData << 2 & 0x3C;
                $dat['index'] = 255;
                $dat['heading'] = $this->hdng;
                break;

            case self::$OBJ_REAL_OBJECT:
                $dat['flags'] = $this->colour;
                $dat['index'] = $this->typeData;
                break;
            case self::$OBJ_START:
                $dat['flags'] = 0x80;
                $dat['index'] = 0;
                break;
            case self::$OBJ_CHECK_1:
                $dat['flags'] = $this->typeData << 2 & 0x3C | 0x81;
                $dat['index'] = 0;
                break;
            case self::$OBJ_CHECK_2:
                $dat['flags'] = $this->typeData << 2 & 0x3C | 0x82;
                $dat['index'] = 0;
                break;
            case self::$OBJ_CHECK_3:
                $dat['flags'] = $this->typeData << 2 & 0x3C | 0x83;
                $dat['index'] = 0;
                break;
            case self::$OBJ_FINISH:
                $dat['flags'] = $this->typeData << 2 & 0x3C | 0x80;
                $dat['index'] = 0;
                break;

            default:
                // unknown objects...
                if (is_array($this->type)) {
                    $dat['flags'] = $this->type[0];
                    $dat['index'] = $this->type[1];
                }
        }

        // default heading calculation
        if (!isset($dat['heading'])) {
            $dat['heading'] = ($this->hdng/* + 180*/) * 256 / 360;
        }

        return $dat;
    }

    /**
     * Set the heading in deg.
     * Normalizes the heading to use the lfs notation between -180° and 180°.
     */
    private function setHeading($val) {
        if ($this->type == self::$OBJ_ROUTE_CHECK) {
            throw new Exception('Trying to set heading on route checker object. Use setRouteIndex instead.');
        }

        if (!is_numeric($val)) {
            throw new Exception('Invalid heading index.');
        }

        // val must be between -180 and 180
        $deg = $val;
        while ($deg < -179) {
            $deg += 360;
        }
        while ($deg > 180) {
            $deg -= 360;
        }

        $this->hdng = $deg;
    }

    /**
     * Set the route index if the object is a route check.
     */
    private function setRouteIndex($val) {
        if ($this->type != self::$OBJ_ROUTE_CHECK) {
            throw new Exception('Trying to set route index on a non route checker object. Use setHeading instead.');
        }

        if (!is_int($val) || $val < 0 || $val > 90) { // TODO check what's the actual max value
            throw new Exception('Invalid route index.');
        }

        $this->hdng = $val;
    }

    public function x()
    {
        return $this->x;
    }
    public function setX($x)
    {
        $this->x = $x;
    }

    public function y()
    {
        return $this->y;
    }
    public function setY($y)
    {
        $this->y = $y;
    }
    public function z()
    {
        return $this->z;
    }
    public function setZ($z)
    {
        $this->z = $z;
    }
    public function heading()
    {
        return $this->hdng;
    }
    public function type()
    {
        return $this->type;
    }
    public function typeData()
    {
        return $this->typeData;
    }
    public function colour()
    {
        return $this->colour;
    }
    public function index()
    {
        if ($this->index == -1)
        {
            $dat = $this->dataForType();
            $this->index = $dat['index'];
        }

        return $this->index;
    }

    public static $AXO_CHALK_LINE = 4;
    public static $AXO_CHALK_LINE2 = 5;
    public static $AXO_CHALK_AHEAD = 6;
    public static $AXO_CHALK_AHEAD2 = 7;
    public static $AXO_CHALK_LEFT = 8;
    public static $AXO_CHALK_LEFT2 = 9;
    public static $AXO_CHALK_LEFT3 = 10;
    public static $AXO_CHALK_RIGHT = 11;
    public static $AXO_CHALK_RIGHT2 = 12;
    public static $AXO_CHALK_RIGHT3 = 13;
    public static $AXO_14 = 14;
    public static $AXO_15 = 15;
    public static $AXO_16 = 16;
    public static $AXO_17 = 17;
    public static $AXO_18 = 18;
    public static $AXO_19 = 19;
    public static $AXO_CONE_RED = 20;
    public static $AXO_CONE_RED2 = 20;
    public static $AXO_CONE_RED3 = 22;
    public static $AXO_CONE_BLUE = 23;
    public static $AXO_CONE_BLUE2 = 24;
    public static $AXO_CONE_GREEN = 25;
    public static $AXO_CONE_GREEN2 = 26;
    public static $AXO_CONE_ORANGE = 27;
    public static $AXO_CONE_WHITE = 28;
    public static $AXO_CONE_YELLOW = 29;
    public static $AXO_CONE_YELLOW2 = 30;
    public static $AXO_31 = 31;
    public static $AXO_32 = 32;
    public static $AXO_33 = 33;
    public static $AXO_34 = 34;
    public static $AXO_35 = 35;
    public static $AXO_36 = 36;
    public static $AXO_37 = 37;
    public static $AXO_38 = 38;
    public static $AXO_39 = 39;
    public static $AXO_CONE_PTR_RED = 40;
    public static $AXO_CONE_PTR_BLUE = 41;
    public static $AXO_CONE_PTR_GREEN = 42;
    public static $AXO_CONE_PTR_YELLOW = 43;
    public static $AXO_44 = 44;
    public static $AXO_45 = 45;
    public static $AXO_46 = 46;
    public static $AXO_47 = 47;
    public static $AXO_TYRE_SINGLE = 48;
    public static $AXO_TYRE_STACK2 = 49;
    public static $AXO_TYRE_STACK3 = 50;
    public static $AXO_TYRE_STACK4 = 51;
    public static $AXO_TYRE_SINGLE_BIG = 52;
    public static $AXO_TYRE_STACK2_BIG = 53;
    public static $AXO_TYRE_STACK3_BIG = 54;
    public static $AXO_TYRE_STACK4_BIG = 55;
    public static $AXO_56 = 56;
    public static $AXO_57 = 57;
    public static $AXO_58 = 58;
    public static $AXO_59 = 59;
    public static $AXO_60 = 60;
    public static $AXO_61 = 61;
    public static $AXO_62 = 62;
    public static $AXO_63 = 63;
    public static $AXO_MARKER_CURVE_L = 64;
    public static $AXO_MARKER_CURVE_R = 65;
    public static $AXO_MARKER_L = 66;
    public static $AXO_MARKER_R = 67;
    public static $AXO_MARKER_HARD_L = 68;
    public static $AXO_MARKER_HARD_R = 69;
    public static $AXO_MARKER_L_R = 70;
    public static $AXO_MARKER_R_L = 71;
    public static $AXO_MARKER_S_L = 72;
    public static $AXO_MARKER_S_R = 73;
    public static $AXO_MARKER_S2_L = 74;
    public static $AXO_MARKER_S2_R = 75;
    public static $AXO_MARKER_U_L = 76;
    public static $AXO_MARKER_U_R = 77;
    public static $AXO_78 = 78;
    public static $AXO_79 = 79;
    public static $AXO_80 = 80;
    public static $AXO_81 = 81;
    public static $AXO_82 = 82;
    public static $AXO_83 = 83;
    public static $AXO_DIST25 = 84;
    public static $AXO_DIST50 = 85;
    public static $AXO_DIST75 = 86;
    public static $AXO_DIST100 = 87;
    public static $AXO_DIST125 = 88;
    public static $AXO_DIST150 = 89;
    public static $AXO_DIST200 = 90;
    public static $AXO_DIST250 = 91;
    public static $AXO_92 = 92;
    public static $AXO_93 = 93;
    public static $AXO_94 = 94;
    public static $AXO_95 = 95;
    public static $AXO_ARMCO1 = 96;
    public static $AXO_ARMCO3 = 97;
    public static $AXO_ARMCO5 = 98;
    public static $AXO_99 = 99;
    public static $AXO_100 = 100;
    public static $AXO_101 = 101;
    public static $AXO_102 = 102;
    public static $AXO_103 = 103;
    public static $AXO_BARRIER_LONG = 104;
    public static $AXO_BARRIER_RED = 105;
    public static $AXO_BARRIER_WHITE = 106;
    public static $AXO_107 = 107;
    public static $AXO_108 = 108;
    public static $AXO_109 = 109;
    public static $AXO_110 = 110;
    public static $AXO_111 = 111;
    public static $AXO_BANNER1 = 112;
    public static $AXO_BANNER2 = 113;
    public static $AXO_114 = 114;
    public static $AXO_115 = 115;
    public static $AXO_116 = 116;
    public static $AXO_117 = 117;
    public static $AXO_118 = 118;
    public static $AXO_119 = 119;
    public static $AXO_RAMP1 = 114;
    public static $AXO_RAMP2 = 115;
    public static $AXO_122 = 122;
    public static $AXO_123 = 123;
    public static $AXO_124 = 124;
    public static $AXO_125 = 125;
    public static $AXO_126 = 126;
    public static $AXO_127 = 127;
    public static $AXO_SPEED_HUMP_10M = 128;
    public static $AXO_SPEED_HUMP_6M = 129;
    public static $AXO_130 = 130;
    public static $AXO_131 = 131;
    public static $AXO_132 = 132;
    public static $AXO_133 = 133;
    public static $AXO_134 = 134;
    public static $AXO_135 = 135;
    public static $AXO_POST_GREEN = 136;
    public static $AXO_POST_ORANGE = 137;
    public static $AXO_POST_RED = 138;
    public static $AXO_POST_WHITE = 139;
    public static $AXO_140 = 140;
    public static $AXO_141 = 141;
    public static $AXO_142 = 142;
    public static $AXO_143 = 143;
    public static $AXO_BALE = 144;
    public static $AXO_145 = 145;
    public static $AXO_146 = 146;
    public static $AXO_147 = 147;
    public static $AXO_RAILING = 148;
    public static $AXO_START_LIGHTS = 149;
    public static $AXO_150 = 150;
    public static $AXO_151 = 151;
    public static $AXO_152 = 152;
    public static $AXO_153 = 153;
    public static $AXO_154 = 154;
    public static $AXO_155 = 155;
    public static $AXO_156 = 156;
    public static $AXO_157 = 157;
    public static $AXO_158 = 158;
    public static $AXO_159 = 159;
    public static $AXO_SIGN_KEEP_LEFT = 160;
    public static $AXO_SIGN_KEEP_RIGHT = 161;
    public static $AXO_162 = 162;
    public static $AXO_163 = 163;
    public static $AXO_164 = 164;
    public static $AXO_165 = 165;
    public static $AXO_166 = 166;
    public static $AXO_167 = 167;
    public static $AXO_SIGN_SPEED_80 = 168;
    public static $AXO_SIGN_SPEED_50 = 169;
    public static $AXO_170 = 170;
    public static $AXO_171 = 171;
    public static $AXO_CONCRETE_SLAB = 172;
    public static $AXO_CONCRETE_RAMP = 173;
    public static $AXO_CONCRETE_WALL = 174;
    public static $AXO_CONCRETE_PILLAR = 175;
    public static $AXO_CONCRETE_SLAB_WALL = 176;
    public static $AXO_CONCRETE_RAMP_WALL = 177;
    public static $AXO_CONCRETE_SHORT_SLAB_WALL = 178;
    public static $AXO_CONCRETE_WEDGE = 179;
    public static $AXO_180 = 180;
    public static $AXO_181 = 181;
    public static $AXO_182 = 182;
    public static $AXO_183 = 183;
    public static $AXO_START_POSITION = 184;
    public static $AXO_PIT_START_POINT = 185;
    public static $AXO_PIT_STOP_BOX = 186;
    public static $AXO_187 = 187;
    public static $AXO_188 = 188;
    public static $AXO_189 = 189;
    public static $AXO_190 = 190;
    public static $AXO_191 = 191;

    public static $TC_BLACK = 0;
    public static $TC_WHITE = 1;
    public static $TC_RED = 2;
    public static $TC_BLUE = 3;
    public static $TC_GREEN = 4;
    public static $TC_YELLOW = 5;

    public static $CC_WHITE = 0;
    public static $CC_RED = 1;
    public static $CC_BLUE = 2;
    public static $CC_YELLOW = 3;

    public static $REV_AXO = array('AXO_NULL','AXO_1','AXO_2','AXO_3','AXO_CHALK_LINE','AXO_CHALK_LINE2','AXO_CHALK_AHEAD','AXO_CHALK_AHEAD2','AXO_CHALK_LEFT','AXO_CHALK_LEFT2','AXO_CHALK_LEFT3','AXO_CHALK_RIGHT','AXO_CHALK_RIGHT2','AXO_CHALK_RIGHT3','AXO_14','AXO_15','AXO_16','AXO_17','AXO_18','AXO_19','AXO_CONE_RED','AXO_CONE_RED2','AXO_CONE_RED3','AXO_CONE_BLUE','AXO_CONE_BLUE2','AXO_CONE_GREEN','AXO_CONE_GREEN2','AXO_CONE_ORANGE','AXO_CONE_WHITE','AXO_CONE_YELLOW','AXO_CONE_YELLOW2','AXO_31','AXO_32','AXO_33','AXO_34','AXO_35','AXO_36','AXO_37','AXO_38','AXO_39','AXO_CONE_PTR_RED','AXO_CONE_PTR_BLUE','AXO_CONE_PTR_GREEN','AXO_CONE_PTR_YELLOW','AXO_44','AXO_45','AXO_46','AXO_47','AXO_TYRE_SINGLE','AXO_TYRE_STACK2','AXO_TYRE_STACK3','AXO_TYRE_STACK4','AXO_TYRE_SINGLE_BIG','AXO_TYRE_STACK2_BIG','AXO_TYRE_STACK3_BIG','AXO_TYRE_STACK4_BIG','AXO_56','AXO_57','AXO_58','AXO_59','AXO_60','AXO_61','AXO_62','AXO_63','AXO_MARKER_CURVE_L','AXO_MARKER_CURVE_R','AXO_MARKER_L','AXO_MARKER_R','AXO_MARKER_HARD_L','AXO_MARKER_HARD_R','AXO_MARKER_L_R','AXO_MARKER_R_L','AXO_MARKER_S_L','AXO_MARKER_S_R','AXO_MARKER_S2_L','AXO_MARKER_S2_R','AXO_MARKER_U_L','AXO_MARKER_U_R','AXO_78','AXO_79','AXO_80','AXO_81','AXO_82','AXO_83','AXO_DIST25','AXO_DIST50','AXO_DIST75','AXO_DIST100','AXO_DIST125','AXO_DIST150','AXO_DIST200','AXO_DIST250','AXO_92','AXO_93','AXO_94','AXO_95','AXO_ARMCO1','AXO_ARMCO3','AXO_ARMCO5','AXO_99','AXO_100','AXO_101','AXO_102','AXO_103','AXO_BARRIER_LONG','AXO_BARRIER_RED','AXO_BARRIER_WHITE','AXO_107','AXO_108','AXO_109','AXO_110','AXO_111','AXO_BANNER1','AXO_BANNER2','AXO_114','AXO_115','AXO_116','AXO_117','AXO_118','AXO_119','AXO_RAMP1','AXO_RAMP2','AXO_122','AXO_123','AXO_124','AXO_125','AXO_126','AXO_127','AXO_SPEED_HUMP_10M','AXO_SPEED_HUMP_6M','AXO_130','AXO_131','AXO_132','AXO_133','AXO_134','AXO_135','AXO_POST_GREEN','AXO_POST_ORANGE','AXO_POST_RED','AXO_POST_WHITE','AXO_140','AXO_141','AXO_142','AXO_143','AXO_BALE','AXO_145','AXO_146','AXO_147','AXO_RAILING','AXO_START_LIGHTS','AXO_150','AXO_151','AXO_152','AXO_153','AXO_154','AXO_155','AXO_156','AXO_157','AXO_158','AXO_159','AXO_SIGN_KEEP_LEFT','AXO_SIGN_KEEP_RIGHT','AXO_162','AXO_163','AXO_164','AXO_165','AXO_166','AXO_167','AXO_SIGN_SPEED_80','AXO_SIGN_SPEED_50','AXO_170','AXO_171','AXO_CONCRETE_SLAB','AXO_CONCRETE_RAMP','AXO_CONCRETE_WALL','AXO_CONCRETE_PILLAR','AXO_CONCRETE_SLAB_WALL','AXO_CONCRETE_RAMP_WALL','AXO_CONCRETE_SHORT_SLAB_WALL','AXO_CONCRETE_WEDGE','AXO_180','AXO_181','AXO_182','AXO_183','AXO_START_POSITION','AXO_PIT_START_POINT','AXO_PIT_STOP_BOX','AXO_187','AXO_188','AXO_189','AXO_190','AXO_191');
    public static $REV_TC = array('TC_BLACK','TC_WHITE','TC_RED','TC_BLUE','TC_GREEN','TC_YELLOW');
    public static $REV_CC = array('CC_WHITE','CC_RED','CC_BLUE','CC_YELLOW');

    public static $Objects = array(
        0 => 'Scenery Object',
        4 => 'Long Chalk Line',
        5 => 'Short Chalk Line',
        6 => 'Short Ahead Arrow',
        7 => 'Long Ahead Arrow',
        8 => 'Short Left Curve Arrow',
        9 => 'Left Turn Arrow',
        10 => 'Long Left Curve Arrow',
        11 => 'Short Right Curve Arrow',
        12 => 'Right Turn Arrow',
        13 => 'Long Right Curve Arrow',
        20 => 'Red+White Cone',
        21 => 'Red Cone',
        22 => 'Striped Red Cone',
        23 => 'Striped Blue Cone',
        24 => 'Blue Cone',
        25 => 'Striped Green Cone',
        26 => 'Green Cone',
        27 => 'Orange Cone',
        28 => 'White Cone',
        29 => 'Striped Yellow Cone',
        30 => 'Yellow Cone',
        40 => 'Red Directional Cone',
        41 => 'Blue Directional Cone',
        42 => 'Green Directional Cone',
        43 => 'Yellow Directional Cone',
        48 => 'Single Tire',
        49 => 'Tire Stack of 2',
        50 => 'Tire Stack of 3',
        51 => 'Tire Stack of 4',
        52 => 'Big Single Tire',
        53 => 'Big Tire Stack of 2',
        54 => 'Big Tire Stack of 3',
        55 => 'Big Tire Stack of 4',
        64 => 'Left Curve Marker',
        65 => 'Right Curve Marker',
        66 => 'Left Turn Marker',
        67 => 'Right Turn Marker',
        68 => 'Hard Left Turn Marker',
        69 => 'Hard Right Turn Marker',
        70 => 'Left->Right Road Marker',
        71 => 'Right->Left Road Marker',
        72 => 'U-Turn->Right Turn Marker',
        73 => 'U-Turn->Left Turn Marker',
        74 => 'Left Winding Turn Marker',
        75 => 'Right Winding Turn Marker',
        76 => 'Left U-Turn Marker',
        77 => 'Right U-Turn Marker',
        84 => '25m Sign',
        85 => '50m Sign',
        86 => '75m Sign',
        87 => '100m Sign',
        88 => '125m Sign',
        89 => '150m Sign',
        90 => '200m Sign',
        91 => '250m Sign',
        96 => 'Short Railing',
        97 => 'Medium Railing',
        98 => 'Long Railing',
        104 => 'Long Barrier',
        105 => 'Red Barrier',
        106 => 'White Barrier',
        112 => 'Banner',
        113 => 'Banner',
        120 => 'Ramp',
        121 => 'Wide Ramp',
        128 => '10m Speed Bump',
        129 => '6m Speed Bump',
        136 => 'Green Post',
        137 => 'Orange Post',
        138 => 'Red Post',
        139 => 'White Post',
        144 => 'Hay Bale',
        148 => 'Railing',
        160 => 'Keep Left Sign',
        161 => 'Keep Right Sign',
        168 => '80 KM/H Sign',
        169 => '50 KM/H Sign',
        172 => 'Concrete Slab',
        173 => 'Concrete Ramp',
        174 => 'Concrete Wall',
        175 => 'Concrete Pillar',
        176 => 'Concrete Slab Wall',
        177 => 'Concrete Ramp Wall',
        178 => 'Concrete Short Slab Wall',
        179 => 'Concrete Wedge'
    );
}

?>
