package com.sfnt.ldk.sample;

import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.methods.CloseableHttpResponse;
import com.google.gson.Gson;

import com.sfnt.ldk.api.LdkRuntimeRestAPI;
import com.sfnt.ldk.model.ClientInfo;
import com.sfnt.ldk.model.FeaturesResponse;
import com.sfnt.ldk.model.KeysResponse;
import com.sfnt.ldk.model.LicenseRequest;
import com.sfnt.ldk.model.LicenseResponse;
import com.sfnt.ldk.model.LogoutResponse;
import com.sfnt.ldk.model.MemoriesResponse;
import com.sfnt.ldk.model.ProductsResponse;
import com.sfnt.ldk.model.ReadMemoryResponse;
import com.sfnt.ldk.model.Scope;
import com.sfnt.ldk.util.ServiceUtil;

public class Sample {

	private static String clientIdentity = "";
	private static String vendorId = "37515";
	private static String featureId = "0";
	private static String endpointScheme = "http";
	private static String serverAddr = "localhost";
	private static String serverPort = "1947";
	private static String userName = "";
	private static String keyId = "";
	private static String productId = "";
	private static String userId = "";
	private static String clientId = "";
	private static String clientSecret = "";
	private static String accessTokenUrl = "";
	private static String authType = "";
	private static String memoryId = "";
	private static String offset = "";
	private static String length = "";
	
	private static Boolean fullInfo = false;
	private static Integer keepAliveTimeout = null;

	/**
	 * Loads parameters
	 * 
	 * @throws Exception
	 */
	public static void loadProperties() throws Exception {
		Properties props = new Properties();
		InputStream in = ServiceUtil.getInputStream("configure.properties");
		props.load(in);
		vendorId = props.getProperty("vendorId");
		clientIdentity = props.getProperty("clientIdentity");
		featureId = props.getProperty("featureId");
		keyId = props.getProperty("keyId");
		productId = props.getProperty("productId");
		endpointScheme = props.getProperty("endpointScheme");
		serverAddr = props.getProperty("serverAddr");
		serverPort = props.getProperty("serverPort");
		authType = props.getProperty("authType");
		userId = props.getProperty("userId");
		clientId = props.getProperty("clientId");
		clientSecret = props.getProperty("clientSecret");
		accessTokenUrl = props.getProperty("accessTokenUrl");
		if(props.getProperty("fullInfo") != null && props.getProperty("fullInfo").equalsIgnoreCase("true"))
			fullInfo = true;
		userName = System.getProperty("user.name");
		memoryId = props.getProperty("memoryId");
		offset = props.getProperty("offset");
		length = props.getProperty("length");

    String kt = props.getProperty("keepAliveTimeout");
    if (kt != null && !kt.isEmpty()) {
        try {
            keepAliveTimeout = Integer.parseInt(kt);
        } catch (NumberFormatException nfe) {
            Logger.getLogger("java_ws_sample")
                    .log(Level.WARNING, "Invalid keepAliveTimeout in configure.properties: {0}", kt);
        }
    }
	}

	public static String getHostName() {
		try {
			InetAddress address = InetAddress.getLocalHost();
			return address.getHostName();
		} catch (UnknownHostException e) {
			return "localhost";
		}
	}

	public static String getDomainName() {
		try {
			InetAddress address = InetAddress.getLocalHost();
			return address.getCanonicalHostName();
		} catch (UnknownHostException e) {
			return "";
		}
	}
	
	public static String getAccessToken() {
		try {
			CloseableHttpClient httpClient = HttpClients.createDefault();
			
			HttpPost httpPost = new HttpPost(accessTokenUrl);
			
			httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
			List<NameValuePair> data = new ArrayList<>();
			data.add(new BasicNameValuePair("grant_type", "client_credentials"));
			data.add(new BasicNameValuePair("client_id", clientId));
			data.add(new BasicNameValuePair("client_secret", clientSecret));
			
			httpPost.setEntity(new UrlEncodedFormEntity(data, "UTF-8"));
			CloseableHttpResponse response = httpClient.execute(httpPost);
			
			Gson gson = new Gson();
			String body = EntityUtils.toString(response.getEntity());
			AccessTokenInfo tokenInfo = gson.fromJson(body, AccessTokenInfo.class);
			response.close();
			httpClient.close();
		
			return tokenInfo.getAccessToken();
		} catch (Exception e) {
			return "";
		}
	}

	public static final String getProcessID() {
		RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
		return runtimeMXBean.getName().split("@")[0];
	}

	/**
	 * The main method to call all web services
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			loadProperties();
			Logger logger = Logger.getLogger("java_ws_sample");
			LdkRuntimeRestAPI api;

			if (authType == null) {
				api = new LdkRuntimeRestAPI(vendorId, null, endpointScheme, serverAddr, serverPort);
			}
			else if (authType.equals("identity")) {
				api = new LdkRuntimeRestAPI(vendorId, clientIdentity, endpointScheme, serverAddr,
					serverPort);
			}
			else if (authType.equals("accesstoken")) {
				api = new LdkRuntimeRestAPI(vendorId, getAccessToken(), userId, endpointScheme,
					serverAddr, serverPort);
			}
			else {
				logger.log(Level.SEVERE, "Invalid auth type!");
				return;
			}
			logger.log(Level.INFO, "Begin Calling Web service");
			logger.log(Level.INFO, "Start Call Login");
			LicenseRequest request = new LicenseRequest();
			request.setFeatureId(Integer.parseInt(featureId));
			request.setFullInfo(fullInfo);
			if (keepAliveTimeout != null) {
                request.setKeepAliveTimeout(keepAliveTimeout);
			}
			ClientInfo clientInfo = new ClientInfo();
			clientInfo.setDomainName(getDomainName());
			clientInfo.setHostName(getHostName());
			clientInfo.setUserName(userName);
			clientInfo.setMachineId(getHostName());
			clientInfo.setProcessId(getProcessID());
			clientInfo.setClientDateTime(api.getCurrentDate());
			request.setClientInfo(clientInfo);
			Scope scope = new Scope();
			List<String> keyIdList = null;
			if (keyId != null && !keyId.isEmpty()) {
				keyIdList = new ArrayList<>();
				keyIdList.add(keyId);
				scope.setKeyId(keyIdList);
			}
			List<Integer> productIdList = null;
			if (productId != null && !productId.isEmpty()) {
				productIdList = new ArrayList<>();
				productIdList.add(Integer.parseInt(productId));
				scope.setProductId(productIdList);
			}
			if(keyIdList != null || productIdList != null)
				request.setScope(scope);

			LicenseResponse loginResponse = api.login(request);
			String sessionId = "";
			if (loginResponse != null) {
				logger.log(Level.INFO, "Login result - \n{0}", loginResponse);
				sessionId = loginResponse.getSessionId();
			}

			logger.log(Level.INFO, "Start Call getKeyList");
			KeysResponse keys = api.getKeyList(0, 5);
			if (keys != null)
				logger.log(Level.INFO, "getKeyList result - \n{0}", keys);
			logger.log(Level.INFO, "Start Call getProductList");
			ProductsResponse products = api.getProudctList(0, 5);
			if (products != null)
				logger.log(Level.INFO, "getProductList result - \n{0}", products);
			logger.log(Level.INFO, "Start Call getFeatureList");
			FeaturesResponse features = api.getFeatureList(0, 5);
			if (features != null)
				logger.log(Level.INFO, "getFeatureList result - \n{0}", features);
			logger.log(Level.INFO, "Start Call getMemoryList");
			MemoriesResponse memories = api.getMemoryList(0, 5);
			if (memories != null)
				logger.log(Level.INFO, "getMemoryList result - \n{0}", memories);
			if (!sessionId.isEmpty()) {
				logger.log(Level.INFO, "Start Call Refresh Session");
				LicenseResponse refreshResponse = api.refreshSession();
				if (refreshResponse != null)
					logger.log(Level.INFO, "Refresh Session result - \n{0}", refreshResponse);
				logger.log(Level.INFO, "Start Call Read Memory");
				ReadMemoryResponse readMemoryResponse = api.readMemory(Integer.parseInt(memoryId), Integer.parseInt(offset), Integer.parseInt(length));
				if (readMemoryResponse != null)
					logger.log(Level.INFO, "Read Memory result - \n{0}", readMemoryResponse);
				logger.log(Level.INFO, "Start Call Logout");
				LogoutResponse logoutResponse = api.logout();
				if (logoutResponse.getErrorCode() == 0)
					logger.log(Level.INFO, "Logout result - Success");
				else
					logger.log(Level.INFO, "Logout result - \n{0}", logoutResponse);
			}
			logger.log(Level.INFO, "End Calling Web service");
		} catch (Exception e) {
			Logger logger = Logger.getLogger("java_ws_sample");
			logger.log(Level.INFO, e.getMessage());
		}
	}

}
