package com.hp.isomorphic.client.issues;

import java.util.HashMap;
import java.util.Map;

import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONValue;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.data.DataSource;
import com.smartgwt.client.data.DataSourceField;
import com.smartgwt.client.data.OperationBinding;
import com.smartgwt.client.data.XMLTools;
import com.smartgwt.client.types.DSDataFormat;
import com.smartgwt.client.types.DSOperationType;
import com.smartgwt.client.types.DSProtocol;
import com.smartgwt.client.widgets.grid.ListGridRecord;

public class PMTableDataSource extends DataSource {
	private static final String COUNT_CLAUSE = "count="; //$NON-NLS-1$
	private static final String START_CLAUSE = "start="; //$NON-NLS-1$

	PMTableDataSource(String url, String recordXPath, DataSourceField[] fields) {
		setFields(fields);

		OperationBinding[] bindings = new OperationBinding[4];
		bindings[0] = new OperationBinding();
		bindings[0].setOperationType(DSOperationType.FETCH);
		bindings[0].setDataProtocol(DSProtocol.GETPARAMS);
		bindings[1] = new OperationBinding();
		bindings[1].setOperationType(DSOperationType.ADD);
		bindings[1].setDataProtocol(DSProtocol.CLIENTCUSTOM);
		bindings[2] = new OperationBinding();
		bindings[2].setOperationType(DSOperationType.REMOVE);
		bindings[2].setDataProtocol(DSProtocol.CLIENTCUSTOM);
		bindings[3] = new OperationBinding();
		bindings[3].setOperationType(DSOperationType.UPDATE);
		bindings[3].setDataProtocol(DSProtocol.CLIENTCUSTOM);
		setOperationBindings(bindings);
		
		setDataFormat(DSDataFormat.JSON);
		setDataURL("/rest/" + url);
		setRecordXPath(recordXPath);
	}
	
	@Override
	protected Object transformRequest(DSRequest request) {
		// request JSON data from the server
		Map<String,String> headers = new HashMap<>();
		headers.put("Content-Type", "application/json");	//$NON-NLS-1$	//$NON-NLS-2$
		headers.put("Accept", "application/json");	//$NON-NLS-1$	//$NON-NLS-2$	
		request.setHttpHeaders(headers);
		
		switch (request.getOperationType()) {
		case FETCH: {
			String limitClause = generateLimitClause(request);
			
			String actionUrl = getDataURL();
			actionUrl = addClause(actionUrl, limitClause);
			request.setActionURL(actionUrl);
			return null;
		}
		
		case ADD: {
			ListGridRecord r = new ListGridRecord(request.getData());
			DSResponse dsResponse = new DSResponse(getID(), DSOperationType.ADD, r);
			dsResponse.setStatus(0);
			processResponse(request.getRequestId(), dsResponse);
			return dsResponse.getData();
		}
		
		case UPDATE: {
			ListGridRecord r = new ListGridRecord(request.getData());
			DSResponse dsResponse = new DSResponse(getID(), DSOperationType.UPDATE, r);
			dsResponse.setStatus(0);
			processResponse(request.getRequestId(), dsResponse);
			return dsResponse.getData();
		}
			
		case REMOVE: {
			ListGridRecord r = new ListGridRecord(request.getData());
			DSResponse dsResponse = new DSResponse(getID(), DSOperationType.REMOVE, r);
			dsResponse.setStatus(0);
			processResponse(request.getRequestId(), dsResponse);
			return dsResponse.getData();
		}
			
		default:
			return null;
		}
	}

	@Override
	protected void transformResponse(DSResponse response, DSRequest request, Object data) {
		DSOperationType operationType = request.getOperationType();

		if (operationType == DSOperationType.FETCH) {
			if (data == null) {
			}
			else {
				Integer total = null;
				JSONArray info = XMLTools.selectObjects(data, "Jobs/totalJobCount");
				JSONValue jsonValue = info.get(0);
				if (jsonValue != null) {
					JSONNumber number = jsonValue.isNumber();
					if (number != null) {
						total = (int) Math.round(number.doubleValue());
					}
				}

				Integer start = null;
				info = XMLTools.selectObjects(data, "Jobs/listStart");
				jsonValue = info.get(0);
				if (jsonValue != null) {
					JSONNumber number = jsonValue.isNumber();
					if (number != null) {
						start = (int) Math.round(number.doubleValue());
					}
				}

				Integer count = null;
				info = XMLTools.selectObjects(data, "Jobs/listCount");
				jsonValue = info.get(0);
				if (jsonValue != null) {
					JSONNumber number = jsonValue.isNumber();
					if (number != null) {
						count = (int) Math.round(number.doubleValue());
					}
				}

				if (total != null) {
					response.setTotalRows(total);
				}
				
				if (start != null) {
					response.setStartRow(start);
					
					if (count != null) {
						response.setEndRow(start + count);
					}
				}
			}
		}
		else { 
			super.transformResponse(response, request, data);
		}
	}
	
	private String addClause(String url, String clause) {
		if( clause == null ) return url;
		url = url + ( url.contains("?") ? "&" : "?" ) + clause; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		return url;
	}

	private String generateLimitClause(DSRequest request) {
		Integer start = request.getStartRow();
		if (start == null) {
			start = 0;
		}
		Integer end = request.getEndRow();
		int count = -1;
		if( end != null ) {
			count = end - start;
		}

		return START_CLAUSE + start + "&" + COUNT_CLAUSE + count; //$NON-NLS-1$
	}
}
