/*
 * Copyright (c) 2013-2015 Cinchapi, Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.cinchapi.concourse.server.http.routers;

import java.nio.ByteBuffer;

import org.cinchapi.concourse.Timestamp;
import org.cinchapi.concourse.server.ConcourseServer;
import org.cinchapi.concourse.server.GlobalState;
import org.cinchapi.concourse.server.http.Endpoint;
import org.cinchapi.concourse.server.http.HttpRequests;
import org.cinchapi.concourse.server.http.Router;
import org.cinchapi.concourse.thrift.AccessToken;
import org.cinchapi.concourse.util.ByteBuffers;
import org.cinchapi.concourse.util.DataServices;

import com.google.common.primitives.Longs;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;

/**
 * The core/default router.
 * 
 * @author Jeff Nelson
 */
public class IndexRouter extends Router {

    /**
     * Construct a new instance.
     * 
     * @param concourse
     */
    public IndexRouter(ConcourseServer concourse) {
        super(concourse);
    }

    @Override
    public void routes() {

        /*
         * ########################
         * #### AUTHENTICATION ####
         * ########################
         */

        /**
         * POST /login
         */
        post(new Endpoint("/login") {

            @Override
            protected JsonElement serve() throws Exception {
                JsonElement body = this.request.bodyAsJson();
                if(body.isJsonObject()) {
                    JsonObject creds = (JsonObject) body;
                    ByteBuffer username = ByteBuffers.fromString(creds.get(
                            "username").getAsString());
                    ByteBuffer password = ByteBuffers.fromString(creds.get(
                            "password").getAsString());
                    AccessToken access = concourse.login(username, password,
                            environment);
                    String token = HttpRequests.encodeAuthToken(access,
                            environment);
                    this.response.cookie("/",
                            GlobalState.HTTP_AUTH_TOKEN_COOKIE, token, 900,
                            false);
                    JsonObject response = new JsonObject();
                    response.add("token", new JsonPrimitive(token));
                    response.add("environment", new JsonPrimitive(environment));

                    return response;
                }
                else {
                    throw new IllegalArgumentException(
                            "Please specify username/password credentials "
                                    + "in a JSON object");
                }
            }

        });

        /**
         * GET /
         */
        get(new Endpoint("/") {

            @Override
            protected JsonElement serve() throws Exception {
                JsonObject payload = new JsonObject();
                payload.addProperty("environment", environment);
                return payload;
            }

        });

        get(new Endpoint("/:arg1") {

            @Override
            protected JsonElement serve() throws Exception {
                // TODO what about transaction
                String arg1 = getParamValue(":arg1");
                String ts = getParamValue("timestamp");
                Long timestamp = ts == null ? null : Timestamp.parse(ts)
                        .getMicros();
                Object data;
                Long record;
                if((record = Longs.tryParse(arg1)) != null) {
                    data = timestamp == null ? concourse.selectRecord(record,
                            accessToken, null, environment) : concourse
                            .selectRecordTime(record, timestamp, accessToken,
                                    null, environment);
                }
                else {
                    data = timestamp == null ? concourse.browseKey(arg1,
                            accessToken, null, environment) : concourse
                            .browseKeyTime(arg1, timestamp, accessToken,
                                    null, environment);
                }          
                return DataServices.gson().toJsonTree(data);
            }

        });

    }
}

@@ -3572,32 +3572,133 @@
 %7D%0A%0A        %7D);%0A%0A
+        /**%0A         * GET /record%5B?timestamp=%3Cts%3E%5D%0A         * GET /key%5B?timestamp=%3Cts%3E%5D%0A         */%0A
         get(new 
@@ -4090,19 +4090,42 @@
     
-Object data
+Long record = Longs.tryParse(arg1)
 ;%0A  
@@ -4138,27 +4138,27 @@
         
-Long record
+Object data
 ;%0A      
@@ -4174,39 +4174,14 @@
  if(
-(
 record
- = Longs.tryParse(arg1))
  != 
@@ -4722,32 +4722,38 @@
 mp, accessToken,
+ null,
 %0A               
@@ -4737,32 +4737,1134 @@
 , null,%0A        
+                            environment);%0A                %7D%0A                return DataServices.gson().toJsonTree(data);%0A            %7D%0A%0A        %7D);%0A%0A        /**%0A         * GET /key/record%5B?timestamp=%3Cts%3E%5D%0A         * GET /record/key%5B?timestamp=%3Cts%3E%5D%0A         */%0A        get(new Endpoint(%22/:arg1/:arg2%22) %7B%0A%0A            @Override%0A            protected JsonElement serve() throws Exception %7B%0A                String arg1 = getParamValue(%22:arg1%22);%0A                String arg2 = getParamValue(%22:arg2%22);%0A                String ts = getParamValue(%22timestamp%22);%0A                Long timestamp = ts == null ? null : Timestamp.parse(ts)%0A                        .getMicros();%0A                Long record = Longs.tryParse(arg1);%0A                String key;%0A                Object data;%0A                if(record != null) %7B%0A                    key = arg2;%0A                %7D%0A                else %7B%0A                    key = arg1;%0A                    record = Long.parseLong(arg2);%0A                %7D%0A                if(timestamp == null) %7B%0A                    data = concourse.selectKeyRecord(key, record, accessToken,%0A
                 
@@ -5912,16 +5912,19 @@
        %7D
+%0A  
         
@@ -5925,16 +5925,186 @@
         
+    else %7B%0A                    data = concourse.selectKeyRecordTime(key, record,%0A                            timestamp, accessToken, null, environment);%0A                %7D
 %0A       

add rest method that matches selecting data from a key/record