/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.dhaval.appstatweb.store;

import com.dhaval.appstats.model.Identity;
import com.dhaval.appstats.model.Location;
import com.dhaval.appstats.model.Stats;
import com.dhaval.appstatweb.marketsearch.MarketApp;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Transaction;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 *
 * @author dhaval
 */
public class DataStore {

    private static final String ENTITY_APPS = "apps";

    public void save(Stats stats){
        if(!hasPhoneIdentity(stats.getIdentity())){
            System.out.println("Registering identity: " + stats.getIdentity());
            savePhoneIdentity(stats.getIdentity());
        }
        savePhoneLocation(stats.getIdentity(), stats.getLocation());
        savePhoneApps(stats.getIdentity(), stats.getProcesses());
    }

    public boolean hasPhoneIdentity(Identity identity){
        DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();
        Query query = new Query("identity");
        query.addFilter("id", Query.FilterOperator.EQUAL, identity.getId());
        PreparedQuery exec = dataStore.prepare(query);
        int count = exec.countEntities();
        return count > 0;
    }

    public void savePhoneIdentity(Identity identity){
        DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();
        Entity entity = new Entity("identity", identity.getId());
        entity.setProperty("id", identity.getId());
        entity.setProperty("time", new Date());
        dataStore.put(entity);
    }

    public void savePhoneLocation(Identity identity, Location location){
        DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();
        Key parent = KeyFactory.createKey("identity", identity.getId());
        Entity entity = new Entity("location", identity.getId(), parent);
        entity.setProperty("id", identity.getId());
        entity.setProperty("lat", location.getLat());
        entity.setProperty("lan", location.getLan());
        entity.setProperty("address", location.getAddress());
        dataStore.put(entity);
    }

    public void savePhoneApps(Identity identity, List<com.dhaval.appstats.model.Process> processes){
        DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();
        Date time = new Date();
        for(com.dhaval.appstats.model.Process process : processes){
            Key parent = KeyFactory.createKey("identity", identity.getId());
            Entity entity = new Entity("process", parent);
            entity.setProperty("id", identity.getId());
            entity.setProperty("name", process.getName());
            entity.setProperty("label", process.getLabel());
            entity.setProperty("time", time);
            dataStore.put(entity);
        }
    }

    public List<Map<String, Object>> getPhoneLocations(){
        List<Map<String, Object>> locations = new ArrayList<Map<String, Object>>();
        DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();
        Query query = new Query("location");
        PreparedQuery exec = dataStore.prepare(query);
        Iterator<Entity> iterator = exec.asIterator();
        while(iterator.hasNext()){
            Entity entity = iterator.next();

            double lat = Double.parseDouble(entity.getProperty("lat").toString());
            double lan = Double.parseDouble(entity.getProperty("lan").toString());
            String addr = entity.getProperty("address").toString();
            String id = entity.getProperty("id").toString();

            Map<String, Object> loc = new HashMap<String, Object>();
            loc.put("id", id);
            loc.put("lat", lat);
            loc.put("lan", lan);
            loc.put("addr", addr);

            locations.add(loc);
        }
        return locations;
    }

    public List<Map<String, Object>> getApplications(String id) {
        List<Map<String, Object>> applications = new ArrayList<Map<String, Object>>();
        DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();

//        Date time = new Date();
//        Calendar cal = Calendar.getInstance();
//        cal.set(Calendar.HOUR_OF_DAY, -24);

        Query query = new Query("process");
        query.addFilter("id", Query.FilterOperator.EQUAL, id);
//        query.addFilter("time", Query.FilterOperator.GREATER_THAN_OR_EQUAL, time);
        PreparedQuery exec = dataStore.prepare(query);

        FetchOptions fo = FetchOptions.Builder.withLimit(20);
        Iterator<Entity> iterator = exec.asIterator(fo);
        while(iterator.hasNext()){
            Entity entity = iterator.next();

            String name = (String) entity.getProperty("name");
            String label = (String) entity.getProperty("label");

            Query appQuery = new Query(ENTITY_APPS);
            appQuery.addFilter("package", Query.FilterOperator.EQUAL, name);
            appQuery.addFilter("native", Query.FilterOperator.EQUAL, false);
            PreparedQuery pAppQuery = dataStore.prepare(appQuery);

            List<Entity> appInfo = pAppQuery.asList(FetchOptions.Builder.withDefaults());
            if(appInfo != null && !appInfo.isEmpty()){
                Map<String, Object> loc = new HashMap<String, Object>();
                loc.put("id", id);
                loc.put("name", name);
                loc.put("label", label);

                Entity app = appInfo.get(0);
                loc.put("rating", app.getProperty("rating"));
                loc.put("vote", app.getProperty("vote"));
                loc.put("downloads", app.getProperty("downloads"));

                applications.add(loc);
            }
        }
        return applications;
    }

    public void saveAppInfo(MarketApp app, boolean nativeApp){
        DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();
        Transaction trx = dataStore.beginTransaction();
        try{
            Entity entity = new Entity(ENTITY_APPS, app.getPackageName());
            entity.setProperty("id", app.getId());
            entity.setProperty("name", app.getName());
            entity.setProperty("native", nativeApp);
            if (!nativeApp) {
                entity.setProperty("package", app.getPackageName());
                entity.setProperty("rating", app.getRating());
                entity.setProperty("vote", app.getRatingCount());
                entity.setProperty("downloads", app.getDownloadText());
            }
            dataStore.put(entity);
            trx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            trx.rollback();
        }
    }

    public boolean containsAppInfo(String packageName){
        DatastoreService dataStore = getDataStoreService();
        Query query = new Query(ENTITY_APPS);
        query.addFilter("package", Query.FilterOperator.EQUAL, packageName);
        PreparedQuery pq = dataStore.prepare(query);

        if(pq.asList(FetchOptions.Builder.withDefaults()).size() > 0){
            return true;
        }else{
            return false;
        }
    }

    public DatastoreService getDataStoreService(){
        return DatastoreServiceFactory.getDatastoreService();
    }
}
