<?php

/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 43):
 * Chris Stretton wrote this file. As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.
 * ----------------------------------------------------------------------------
 */

    
Class GWTemplate {

        private 
$bin "";
        private 
$attribcount 0;
        private 
$attribsize 0;
        private 
$b64 = array("A""B""C""D""E""F""G""H""I""J""K""L""M""N""O""P""Q""R""S""T""U""V""W""X""Y""Z""a""b""c""d""e""f""g""h""i""j""k""l""m""n""o""p""q""r""s""t""u""v""w""x""y""z""0""1""2""3""4""5""6""7""8""9""+""/");

        public 
$attribs = array();
        public 
$skills = array();
        public 
$primary 0;
        public 
$secondary 0;
        public 
$code "";

        public function 
__construct($code "AAAAAAAAAAAAAAA") {
            
$this->code $code;
            
$this->load();
        }

        public function 
parse() { // Legacy function
            
$this->load();
        }

        public function 
load() {
            if (
$this->code == "") {
                throw new 
Exception('No code set');
            }
            
$this->bin $this->b642binstr();
            if (
strlen($this->bin) < 90) {
                throw new 
Exception('Invalid code');
            }
            
$this->primary $this->binstr2int(substr($this->bin64));
            
$this->secondary $this->binstr2int(substr($this->bin104));
            
$this->attribcount $this->binstr2int(substr($this->bin144));
            
$this->attribsize $this->binstr2int(substr($this->bin184));
            
$pos 22;
            for(
$i 0$i $this->attribcount$i ++, $pos += ($this->attribsize 4)) {
                
$this->attribs[$i]['attribute'] = $this->binstr2int(substr($this->bin$pos$this->attribsize));
                
$this->attribs[$i]['value'] = $this->binstr2int(substr($this->bin$pos $this->attribsize4));
            }
            
$this->skillsize $this->binstr2int(substr($this->bin$pos4));
            
$pos += 4;
            for(
$i 0$i 8$i ++, $pos += $this->skillsize) {
                
$this->skills[$i] = $this->binstr2int(substr($this->bin$pos$this->skillsize));
            }
        }

        public function 
save() {
            if (
count($this->skills) < 8) {
                throw new 
Exception('A build requires 8 skills.');
            }
            
$binary "000000";
            
$binary .= $this->int2binstr($this->primary);
            
$binary .= $this->int2binstr($this->secondary);
            
$binary .= $this->int2binstr(count($this->attribs));
            
$size 0;
            
$b2 "";
            foreach (
$this->attribs as $attrib) {
                
$b strlen($this->int2binstr($attrib['attribute']));
                if (
$b $size) {
                    
$size $b;
                }
            }
            foreach (
$this->attribs as $attrib) {
                
$b2 .= $this->int2binstr($attrib['attribute'], $size);
                
$b2 .= $this->int2binstr($attrib['value']);
            }
            
$binary .= $this->int2binstr($size 4);
            
$binary .= $b2;
            
$size 0;
            
$b2 "";
            foreach (
$this->skills as $skill) {
                
$b strlen($this->int2binstr($skill$size));
                if (
$b $size) {
                    
$size $b;
                }
            }
            foreach (
$this->skills as $skill) {
                
$b2 .= $this->int2binstr($skill$size);
            }
            
$binary .= $this->int2binstr($size 8);
            
$binary .= $b2;
            
$this->bin $binary;
            
$this->code $this->binstr2b64();
        }

        private function 
binstr2b64() {
            
$binary $this->bin;
            
$c strlen($binary);
            
$string "";
            for (
$i 0$i $c$i += 6) {
                
$string .= $this->b64[$this->binstr2int(substr($binary$i6))];
            }
            return 
$string;
        }

        private function 
b642binstr() {
            
$string $this->code;
            
$b64 array_flip($this->b64);
            
$c strlen($string);
            
$binary "";
            for (
$i 0$i $c$i ++) {
                
$binary .= $this->int2binstr($b64[$string{$i}], 6);
            }
            return 
$binary;
        }

        private function 
int2binstr($int$padding 4) {
            return 
strrev(str_pad(decbin($int), $padding"0"STR_PAD_LEFT));
        }

        private function 
binstr2int($binary) {
            
$c strlen($binary);
            
$value 0;
            for (
$i 0$i $c$i ++) {
                
$value += $binary{$i} * pow(2$i);
            }
            return 
$value;
        }
    }

?>