package com.socrata.datasync;

import com.socrata.datasync.config.userpreferences.UserPreferences;
import com.socrata.model.importer.Column;
import com.socrata.model.importer.Dataset;
import com.socrata.model.importer.DatasetInfo;
import org.apache.http.HttpException;
import org.apache.http.HttpStatus;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.utils.URIBuilder;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class DatasetUtils {

    private static class DatasetInfoResponseHandler implements ResponseHandler<DatasetInfo> {
        @Override
        public DatasetInfo handleResponse(final HttpResponse response)
            throws ClientProtocolException, IOException {

            StatusLine statusLine = response.getStatusLine();
            int status = statusLine.getStatusCode();
            if (status >= 200 && status < 300) {
                HttpEntity entity = response.getEntity();
                return entity != null ? mapper.readValue(entity.getContent(), DatasetInfo.class) : null;
            } else {
                throw new ClientProtocolException(statusLine.toString());
            }
        }
    }


    private static final String LOCATION_DATATYPE_NAME = "location";

    private static ObjectMapper mapper = new ObjectMapper().enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

    public static <T> T getDatasetInfo(UserPreferences userPrefs, String viewId, final Class<T> typ) throws URISyntaxException, IOException, HttpException {
        String justDomain = getDomainWithoutScheme(userPrefs);
        URI absolutePath = new URIBuilder()
            .setScheme("https")
            .setHost(justDomain)
            .setPath("/api/views/" + viewId)
            .build();

        ResponseHandler<T> handler = new ResponseHandler<T>() {
            @Override
            public T handleResponse(
                final HttpResponse response) throws ClientProtocolException, IOException {
                StatusLine statusLine = response.getStatusLine();
                int status = statusLine.getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity entity = response.getEntity();
                    return entity != null ? mapper.readValue(entity.getContent(), typ) : null;
                } else {
                    throw new ClientProtocolException(statusLine.toString());
                }
            }
        };

        HttpUtility util = new HttpUtility(userPrefs, true);
        T datasetInfo = util.get(absolutePath, "application/json", handler);
        util.close();
        return datasetInfo;
    }

    public static String getDatasetSample(UserPreferences userPrefs, String viewId, int rowsToSample) throws URISyntaxException, IOException, HttpException {
        String justDomain = getDomainWithoutScheme(userPrefs);
        URI absolutePath = new URIBuilder()
            .setScheme("https")
            .setHost(justDomain)
            .setPath("/resource/" + viewId + ".csv")
            .addParameter("$limit",""+rowsToSample)
            .build();

        ResponseHandler<String> handler = new ResponseHandler<String>() {
            @Override
            public String handleResponse(
                final HttpResponse response) throws ClientProtocolException, IOException {
                StatusLine statusLine = response.getStatusLine();
                int status = statusLine.getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity entity = response.getEntity();
                    return entity != null ? EntityUtils.toString(entity) : null;
                } else {
                    throw new ClientProtocolException(statusLine.toString());
                }
            }
        };

        HttpUtility util = new HttpUtility(userPrefs, true);
        String sample = util.get(absolutePath, "application/csv", handler);
        util.close();
        return sample;
    }

    public static String getDomainWithoutScheme(UserPreferences userPrefs){
        return getDomainWithoutScheme(userPrefs.getDomain());
    }

    public static String getDomainWithoutScheme(String domain){
        String[] schemaAndDomain = domain.trim().split("//");
        String justDomain;
        if(schemaAndDomain.length > 0) {
            justDomain = schemaAndDomain[schemaAndDomain.length - 1];
        } else {
            justDomain = schemaAndDomain[0];
        }
        return justDomain.split("[/:]")[0];
    }



    /**
     * Retruns the field name of the row identifier, if there is one, else null
     */
    public static String getRowIdentifierName(Dataset schema) {
        Column rowIdentifierColumn = schema.lookupRowIdentifierColumn();
        if (rowIdentifierColumn == null) {
            return null;
        } else {
            return rowIdentifierColumn.getFieldName();
        }
    }


    /**
     * Returns list of dataset field names in the form: "col1","col2",...
     *
     * @param datasetId
     * @return list of field names or null if there
     */
    public static String getFieldNamesString(UserPreferences userPrefs, String datasetId) throws HttpException, IOException, URISyntaxException {
        Dataset datasetInfo = getDatasetInfo(userPrefs, datasetId, Dataset.class);
        return getFieldNamesString(datasetInfo);
    }

    /**
     * Returns list of dataset field names in the form: "col1","col2",...
     *
     * @param datasetInfo
     * @return list of field names or null if there are none
     */
    public static String getFieldNamesString(Dataset datasetInfo) {
        String columnsValue = "";
        List<Column> columns = datasetInfo.getColumns();
        for(int i = 0; i < columns.size(); i++) {
            if(i > 0)
                columnsValue += ",";
            columnsValue += "\"" + columns.get(i).getFieldName() + "\"";
        }
        return columnsValue;
    }

    /**
     * Returns an array of dataset field names.
     *
     * @param datasetInfo
     * @return array of field names or null if there are none
     */
    public static String[] getFieldNamesArray(Dataset datasetInfo) {
        List<Column> columns = datasetInfo.getColumns();
        String[] columnsArray = new String[columns.size()];
        for(int i = 0; i < columns.size(); i++) {
            columnsArray[i] = columns.get(i).getFieldName();
        }
        return columnsArray;
    }

    /**
     * Returns the set of dataset field names.
     *
     * @param datasetInfo
     * @return array of field names or null if there are none
     */
    public static Set<String> getFieldNamesSet(Dataset datasetInfo) {
        List<Column> columns = datasetInfo.getColumns();
        Set<String> fields = new HashSet<>();
        for(int i = 0; i < columns.size(); i++) {
            fields.add(columns.get(i).getFieldName());
        }
        return fields;
    }

    /**
     * Returns a mapping of dataset field names to their type.
     *
     * @param datasetInfo
     * @return a map of dataset field names to datatypes
     */
    public static Map<String,String> getDatasetTypeMapping(Dataset datasetInfo) {
        List<Column> columns = datasetInfo.getColumns();
        Map<String,String> mapping = new HashMap<>();
        for(Column c : columns) {
            mapping.put(c.getFieldName(), c.getDataTypeName());
        }
        return mapping;
    }

    /**
     * @return true if given dataset has one or more Location columns, false otherwise
     */
    public static boolean hasLocationColumn(Dataset datasetInfo) {
        List<Column> columns = datasetInfo.getColumns();
        for(int i = 0; i < columns.size(); i++) {
            if(columns.get(i).getDataTypeName().equals(LOCATION_DATATYPE_NAME))
                return true;
        }
        return false;
    }
}

@@ -4815,192 +4815,55 @@
 main
-;%0A        if(schemaAndDomain.length %3E 0) %7B%0A            justDomain = schemaAndDomain%5BschemaAndDomain.length - 1%5D;%0A        %7D else %7B%0A            justDomain = schemaAndDomain%5B0%5D;%0A        %7D
+ = schemaAndDomain%5BschemaAndDomain.length - 1%5D;
 %0A   

Clean up a bit of weirdness around splitting