1 var http = require('http');
  2 var OpalRequest = require('./OpalRequest.js').OpalRequest;
  3 var Event = require('../../../lib/core/event/Event.js').Event;
  4 var ErrorEvent = require('../../../lib/core/event/ErrorEvent.js').ErrorEvent;
  5 var EventDispatcher = require('../../../lib/core/event/EventDispatcher.js').EventDispatcher; 
  6 var Class = require('../../../lib/mootools/mootools-node.js').Class;
  7 
  8 /**
  9  * @class OpalLoader
 10  * @extends EventDispatcher
 11  * @requires Class
 12  * @requires OpalRequest
 13  * @requires Event
 14  * @requires ErrorEvent
 15  * @requires EventDispatcher
 16  * @requires http
 17  *
 18  * @param {OpalRequest} request
 19  */
 20 var OpalLoader = function(){
 21 
 22     /** @ignore */
 23     this.Extends = EventDispatcher;
 24 
 25 
 26     /**
 27      * @property {Object} data
 28      */
 29     this.data = {};
 30     
 31     /**
 32      * @private
 33      * @property {Object} _chunks
 34      */
 35     this._chunks = [];
 36 
 37      /**
 38      * @private
 39      * @property {Object} _request
 40      */
 41     this._request = null;
 42 
 43      /**
 44      * @private
 45      * @property {Number} _timeout
 46      */
 47     this._timeout = 15000;
 48 
 49      /**
 50      * @private
 51      * @property {Object} _timer
 52      */
 53     this._timer = null;
 54     
 55 
 56     /** @ignore */
 57     this.initialize = function(request){
 58         this.setRequest(request);
 59     };
 60 
 61     /**
 62      * callback responsible for gathering response chunks
 63      * @private
 64      * @param {Server.HttpResponse} response
 65      */
 66     this._response = function(response){
 67         var self = this;
 68 
 69         if(response.statusCode !== 200){
 70             this._clearTimer();
 71             var event = new ErrorEvent(OpalLoader.ERROR, response.statusCode, -2, 'Wrong HTTP status code');
 72             this.dispatchEvent(event);
 73             return;
 74         }
 75 
 76         response.setEncoding('utf8');
 77         response.addListener('data', function(chunk){
 78             self._chunks.push(chunk);
 79         }).addListener('end', function(){
 80             self._onEnd();
 81         });
 82     };
 83 
 84     /**
 85      * sets timer who is responsible for timeout detection
 86      * @private
 87      * @param {Server.HttpRequest} request
 88      */
 89     this._setTimer = function(request){
 90         var self = this;
 91         this._timer = setTimeout(function(){
 92             request.removeAllListeners('response');
 93             self.dispatchEvent(new ErrorEvent(OpalLoader.ERROR, null, -4, 'Http response timeout'));
 94         }, this.getTimeout());
 95     };
 96 
 97     /**
 98      * clears timer handle that is responsible for timeout detection
 99      * @private
100      */
101     this._clearTimer = function(){
102         clearTimeout(this._timer);
103     };
104 
105     /**
106      * called on request end, when whole data is retreived from server
107      * @private
108      */
109     this._onEnd = function(){
110         this._clearTimer();
111 
112         try {
113             this._data = JSON.parse(this._chunks.join(''));
114         } catch(err) {
115             this.dispatchEvent(new ErrorEvent(OpalLoader.ERROR, {json: this._chunks.join(''), error: err.message}, -3, 'JSON parse error'));
116             return;
117         }
118 
119         if(this._data.hasOwnProperty('error')) {
120             this.dispatchEvent(new ErrorEvent(OpalLoader.ERROR, null, this._data.error.code, this._data.error.message));
121             return;
122         }
123 
124         this.dispatchEvent(new Event(OpalLoader.LOADED, this._data.result));
125     };
126 
127 
128     /**
129      * sets timeout in miliseconds
130      * @param {Number} ms
131      */
132     this.setTimeout = function(ms){
133         this._timeout = ms;
134         return this;
135     };
136 
137     /**
138      * gets timeout in miliseconds
139      * @returns {Number}
140      */
141     this.getTimeout = function(){
142         return this._timeout;
143     };
144 
145     /**
146      * sets request object to process
147      * @param {OpalRequest} request
148      */
149     this.setRequest = function(request){
150         if(request && !(request instanceof OpalRequest)){
151             throw 'Given request is not a instance of OpalRequest';
152         } else if(request) {
153             this._request = request;
154         }        
155     };
156 
157     /**
158      * makes request to the backend system based on the request object
159      * @param {OpalRequest} request
160      */
161     this.load = function(request){
162         this.setRequest(request);
163         
164         if(this._request == null){
165             throw new Error('Request has not been set');
166         }
167 
168         var self = this;
169         
170         var request = http.request({
171             host: this._request.getGatewayHost(),
172             port: this._request.getGatewayPort(),
173             path: this._request.getUrl(),
174             method: this._request.getMethod(),
175             headers: this._request.getHeaders()
176         }, function(response){
177             self._response(response);
178         }).addListener('error', function(e){
179             self._clearTimer();
180             self.dispatchEvent(new ErrorEvent(OpalLoader.ERROR, e, -1, 'Http request error'));
181         });
182 
183         request.write(this._request.getData());
184         request.end();
185 
186         this._setTimer(request);
187     };
188 };
189 
190 OpalLoader = new Class(new OpalLoader());
191 OpalLoader.LOADED = "OpalLoader_LOADED";
192 OpalLoader.ERROR = "OpalLoaded_ERROR";
193 exports.OpalLoader = OpalLoader;