import { Injectable } from '@angular/core';
import { Http, Headers, Response, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { PreferencesProvider } from './preferences-provider';

import 'rxjs/add/operator/toPromise'
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import 'rxjs/add/observable/forkJoin';

@Injectable()
export class OdooProvider {

    url: string;

    constructor(
        public http: Http,
        public preferencesProvider: PreferencesProvider
    ) {
        this.url = preferencesProvider.getHost();
        this.normalizeUrl();
    }

    /**
     *
     */
    private normalizeUrl(): void {
        this.url = (this.url.startsWith('http://') || this.url.startsWith('https://')  ? this.url : 'http://' + this.url) + '/api/';
    }

    /**
     * 
     */
    post(resource: string, data: Array<any>): Promise<any> {
        if (data.length == 0) {
            return;
        }

        let headers = new Headers({
            'Authorization': 'JWT ' + this.preferencesProvider.getToken(),
            'Content-Type': 'application/x-www-form-urlencoded',
            'Cache-Control': 'no-cache'
        });

        let options = new RequestOptions({ headers: headers });

        let toSend: Array<Observable<Response>> = [];
        for (let i = 0; i < data.length; i++) {
            toSend.push(this.http.post(this.url + resource, this.encodeData(data[i]), options));
        }

        return new Promise((resolve, reject) => { 
            Observable.forkJoin(toSend).subscribe(r => { 
                resolve(r);
            }, e => {
                reject(e);
            });
        });
    }

    /**
     *
     */
    private encodeData(data: any): string {
        let body = [];
        for (let field in data) {
            if (['doc_state', "remote_id", "rev"].indexOf(field) != -1) {
                continue;
            }

            body.push(field + "=" + encodeURIComponent(data[field]));
        }

       return body.join("&");
    }
    
    /**
     *
     */
    get(resource: string, id?: number, filter?: Array<[string, string]>): Promise<any> {
        let headers = new Headers({
            'Authorization': 'JWT ' + this.preferencesProvider.getToken()
        });
        
        let options = new RequestOptions({ headers: headers });

        return new Promise((resolve, reject) => {
            this.http.get(this.url + resource, options).toPromise().then(r => { 
                resolve(r.json());
            }).catch(e => { 
                reject(e.json());
            });
        });
    }

    /**
     *
     */
    put(resource: string, data: Array<any>) {
        if (data.length == 0) {
            return;
        }

        let headers = new Headers({
            'Content-Type':  'application/x-www-form-urlencoded',
            'Authorization': 'JWT ' + this.preferencesProvider.getToken()
        });

        let options = new RequestOptions({ headers: headers });

        let toSend: Array<Observable<Response>> = [];
        for (let i = 0; i < data.length; i++) {
            this.encodeData(data[i]);
            toSend.push(this.http.put(this.url + resource + '/' + data[i].remote_id, this.encodeData(data[i]), options));
        }

        return new Promise((resolve, reject) => { 
            Observable.forkJoin(toSend).subscribe(r => { 
                resolve(r);
            }, e => {
                reject(e);
            });
        });
    }

    /**
     *
     */
    delete(resource: string, data: Array<any>) {
        if (data.length == 0) {
            return;
        }

        let headers = new Headers({
            'Content-Type':  'application/x-www-form-urlencoded',
            'Authorization': 'JWT ' + this.preferencesProvider.getToken()
        });

        let options = new RequestOptions({ headers: headers });

        let toSend: Array<Observable<Response>> = [];
        for (let i = 0; i < data.length; i++) {
            this.encodeData(data[i]);
            toSend.push(this.http.delete(this.url + resource + '/' + data[i].remote_id, options));
        }

        return new Promise((resolve, reject) => { 
            Observable.forkJoin(toSend).subscribe(r => { 
                resolve(r);
            }, e => {
                reject(e);
            });
        });
    }
}