1<?php
2
3/**
4 * Instruction re-writer
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Mykola Ostrovskyy <dwpforge@gmail.com>
8 */
9
10if (!class_exists('instruction_rewriter', false)) {
11
12class instruction_rewriter {
13
14    private $correction;
15
16    /**
17     * Constructor
18     */
19    public function __construct() {
20        $this->correction = array();
21    }
22
23    /**
24     *
25     */
26    public function addCorrections($correction) {
27        foreach ($correction as $c) {
28            $this->correction[$c->getIndex()][] = $c;
29        }
30    }
31
32    /**
33     *
34     */
35    public function process(&$instruction) {
36        if (count($this->correction) > 0) {
37            $index = $this->getCorrectionIndex();
38            $corrections = count($index);
39            $instructions = count($instruction);
40            $output = array();
41            for ($c = 0, $i = 0; $c < $corrections; $c++, $i++) {
42                /* Copy all instructions that are before the next correction */
43                for ( ; $i < $index[$c]; $i++) {
44                    $output[] = $instruction[$i];
45                }
46                /* Apply the corrections */
47                $preventDefault = false;
48                foreach ($this->correction[$i] as $correction) {
49                    $preventDefault = ($preventDefault || $correction->apply($instruction, $output));
50                }
51                if (!$preventDefault) {
52                    $output[] = $instruction[$i];
53                }
54            }
55            /* Copy the rest of instructions after the last correction */
56            for ( ; $i < $instructions; $i++) {
57                $output[] = $instruction[$i];
58            }
59            /* Handle appends */
60            if (array_key_exists(-1, $this->correction)) {
61                $this->correction[-1]->apply($instruction, $output);
62            }
63            $instruction = $output;
64        }
65    }
66
67    /**
68     *
69     */
70    private function getCorrectionIndex() {
71        $result = array_keys($this->correction);
72        asort($result);
73        /* Remove appends */
74        if (reset($result) == -1) {
75            unset($result[key($result)]);
76        }
77        return array_values($result);
78    }
79}
80
81class instruction_rewriter_correction {
82
83    protected $index;
84
85    /**
86     * Constructor
87     */
88    public function __construct($index) {
89        $this->index = $index;
90    }
91
92    /**
93     *
94     */
95    public function getIndex() {
96        return $this->index;
97    }
98}
99
100class instruction_rewriter_delete extends instruction_rewriter_correction {
101
102    /**
103     * Constructor
104     */
105    public function __construct($index) {
106        parent::__construct($index);
107    }
108
109    /**
110     *
111     */
112    public function apply($input, &$output) {
113        return true;
114    }
115}
116
117class instruction_rewriter_call_list extends instruction_rewriter_correction {
118
119    private $call;
120
121    /**
122     * Constructor
123     */
124    public function __construct($index) {
125        parent::__construct($index);
126        $this->call = array();
127    }
128
129    /**
130     *
131     */
132    public function addCall($name, $data) {
133        $this->call[] = array($name, $data);
134    }
135
136    /**
137     *
138     */
139    public function addPluginCall($name, $data, $state, $text = '') {
140        $this->call[] = array('plugin', array($name, $data, $state, $text));
141    }
142
143    /**
144     *
145     */
146    public function appendCalls(&$output, $position) {
147        foreach ($this->call as $call) {
148            $output[] = array($call[0], $call[1], $position);
149        }
150    }
151}
152
153class instruction_rewriter_insert extends instruction_rewriter_call_list {
154
155    /**
156     * Constructor
157     */
158    public function __construct($index) {
159        parent::__construct($index);
160    }
161
162    /**
163     *
164     */
165    public function apply($input, &$output) {
166        $this->appendCalls($output, $input[$this->index][2]);
167        return false;
168    }
169}
170
171class instruction_rewriter_append extends instruction_rewriter_call_list {
172
173    /**
174     * Constructor
175     */
176    public function __construct() {
177        parent::__construct(-1);
178    }
179
180    /**
181     *
182     */
183    public function apply($input, &$output) {
184        $lastCall = end($output);
185        $this->appendCalls($output, $lastCall[2]);
186        return false;
187    }
188}
189
190}
191