// Angular dependencies.
import { Injectable } from '@angular/core';
import { Http, URLSearchParams } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { AuthHttp } from 'angular2-jwt';
import 'rxjs/Rx';

// Services.
import { BaseService } from './base.service';
import { ConfigService } from './config.service';

// HTTP JSON headers.
import { jsonHeaders } from '../common/json-headers';

@Injectable()
export class CrudService extends BaseService
{

	// Initialize.
	
 (protected authHttp: AuthHttp, protected http: Http, protected config: ConfigService)
	{
		super(config);
	}

	// Query API for a list of items.
	public GetItems(relativeApiUrl: string, urlParams: Object = {}, filters: Object = {}): Observable<any[]>
	{
		// Get the API URL.
		let apiUrl = this.buildUrl(relativeApiUrl, urlParams);

		// Build search filters.
		let urlSearchParams: URLSearchParams = new URLSearchParams();
		for (let key in filters)
		{
			urlSearchParams.set(key, filters[key]);
		}

		// Send the HTTP request.
		return this.authHttp
			.get(apiUrl, {search: urlSearchParams})
			.map(this.extractData)
			.publishReplay(1)
			.refCount()
			.catch(this.handleError);
	}
	
	// Query API for a specific item.
	public GetItem(relativeApiUrl: string, urlParams: Object = {}, filters: Object = {})
	{
		// Get the API URL.
		let apiUrl = this.buildUrl(relativeApiUrl, urlParams);

		// Build search filters.
		let urlSearchParams: URLSearchParams = new URLSearchParams();
		for (let key in filters)
		{
			urlSearchParams.set(key, filters[key]);
		}

		// Send the HTTP request.
		return this.authHttp
			.get(apiUrl, {search: urlSearchParams})
			.map(this.extractData)
			.catch(this.handleError);
	}

	// Update.
	public Save(relativeApiUrl: string, urlParams: Object = {}, item: any): Observable<any>
	{
		// Get the API URL.
		let apiUrl = this.buildUrl(relativeApiUrl, urlParams);
		
		// Convert the object to a JSON string.
		let body = JSON.stringify(item);

		// Log it.
		console.info(this.constructor.name, 'SAVING', apiUrl);

		if (item._id)
		{
			// Update the existing item.
			return this.authHttp
				.put(apiUrl, body, {headers: jsonHeaders})
				.map(this.extractData)
				.catch(this.handleError);
		}
		else
		{
			// Create a new item.
			return this.authHttp
				.post(apiUrl, body, {headers: jsonHeaders})
				.map(this.extractData)
				.catch(this.handleError);
		}
	}

	// Delete.
	public Delete(relativeApiUrl: string, urlParams: Object = {})
	{
		// Get the API URL.
		let apiUrl = this.buildUrl(relativeApiUrl, urlParams);
		
		// Log it.
		console.warn(this.constructor.name, 'DELETING:', apiUrl);

		// Send the HTTP request.
		return this.authHttp
			.delete(apiUrl)
			.map(this.extractData)
			.catch(this.handleError);
	}
}
constructor