package com.fca.uconnect.global;

import java.io.ByteArrayOutputStream;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

import com.fca.uconnect.global.GlobalUconnectControl.UconnectAny;
import com.fca.uconnect.global.GlobalUconnectControl.UconnectMessage;
import com.fca.uconnect.global.GlobalUconnectExtProvision.ProvisioningPush;
import com.fca.uconnect.global.GlobalUconnectExtProvision.ServiceDescription;
import com.fca.uconnect.global.GlobalUconnectExtProvision.ServiceDescription.ServiceTypeEnum;
import com.fca.uconnect.global.GlobalUconnectExtProvision.ServiceSubscriptionInfo;
import com.fca.uconnect.global.GlobalUconnectExtProvision.WifiConfigSet;
import com.fca.uconnect.global.GlobalUconnectExtProvision.WifiSetting;
import com.fca.uconnect.global.GlobalUconnectExtProvision.WifiSetting.EncryptionEnum;
import com.fca.uconnect.global.GlobalUconnectExtSignature.Signature;
import com.google.protobuf.ByteString;

public class ExampleForSignature {
	private int messageId;
	
	//This method builds Signature message with ProvisionPush .
	public UconnectMessage getProvisionPushMsgWithSignature(String vehicleId, UUID sessionId) {
		messageId++;
		
		ServiceDescription servDesc = ServiceDescription.newBuilder()
				.setExpireTime(1234567890)
				.setServiceType(ServiceTypeEnum.ECALL)
				.build();
		ServiceDescription servDesc1 = ServiceDescription.newBuilder()
				.setExpireTime(1234567890)
				.setServiceType(ServiceTypeEnum.REMOTEENGINESTART)
				.build();
		List<ServiceDescription> services = new ArrayList<ServiceDescription>();
		services.add(servDesc);
		services.add(servDesc1);
		ServiceSubscriptionInfo serviceDesc = ServiceSubscriptionInfo.newBuilder()
				.addAllServices(services).
				build();

		 WifiSetting wifiSetting = WifiSetting.newBuilder()
				 .setEncryption(EncryptionEnum.WEP)
				 .setSsid("FCA")
				 .setPassword("FCAPWD")
				 .build();
		 WifiConfigSet wifiConfigSet = WifiConfigSet.newBuilder()
				 .setWifiSetting(wifiSetting)
				 .build();
		 ProvisioningPush provisioningPush = ProvisioningPush.newBuilder()
				 .setWifiConfigSet(wifiConfigSet)
				 .setServiceSubscriptionInfo(serviceDesc)
				 .build();
		 
		 
	    byte[] signatureValBytes = decodeBase64("-b64");
	    ByteString value = ByteString.copyFrom(signatureValBytes);
		Signature signature = Signature.newBuilder()
				.setSignatureType("Base64")
				.setSignatureValue(value)
				.build();
		UconnectMessage msg = UconnectMessage.newBuilder()
				.setTimestamp(System.currentTimeMillis())
				.setMessageId(messageId)
				.setSessionIdLSB(0)
				.setSessionIdMSB(0)
				.addMessages(UconnectAny.newBuilder().setExtension(GlobalUconnectExtSignature.signature, signature))
				.addMessages(UconnectAny.newBuilder().setExtension(GlobalUconnectExtProvision.provisioningPush, provisioningPush))								
				.build();
		return msg;		
	}

private static int b64d(char i) {
switch (i) {
case 'A': return 0; case 'B': return 1; case 'C': return 2; case 'D': return 3;
case 'E': return 4; case 'F': return 5; case 'G': return 6; case 'H': return 7;
case 'I': return 8; case 'J': return 9; case 'K': return 10; case 'L': return 11;
case 'M': return 12; case 'N': return 13; case 'O': return 14; case 'P': return 15;
case 'Q': return 16; case 'R': return 17; case 'S': return 18; case 'T': return 19;
case 'U': return 20; case 'V': return 21; case 'W': return 22; case 'X': return 23;
case 'Y': return 24; case 'Z': return 25; case 'a': return 26; case 'b': return 27;
case 'c': return 28; case 'd': return 29; case 'e': return 30; case 'f': return 31;
case 'g': return 32; case 'h': return 33; case 'i': return 34; case 'j': return 35;
case 'k': return 36; case 'l': return 37; case 'm': return 38; case 'n': return 39;
case 'o': return 40; case 'p': return 41; case 'q': return 42; case 'r': return 43;
case 's': return 44; case 't': return 45; case 'u': return 46; case 'v': return 47;
case 'w': return 48; case 'x': return 49; case 'y': return 50; case 'z': return 51;
case '0': return 52; case '1': return 53; case '2': return 54; case '3': return 55;
case '4': return 56; case '5': return 57; case '6': return 58; case '7': return 59;
case '8': return 60; case '9': return 61; case '+': return 62; case '/': return 63;
default: return -1;
}
}
	public static byte[] decodeBase64(String s) {
		CharacterIterator it = new StringCharacterIterator(s.trim());
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int i = 0, j = 0;
		for (char ch = it.first(); ch != CharacterIterator.DONE && ch != '='; ch = it.next()) {
		  int v = b64d(ch);
		  if (v >= 0) {
		    i = (i << 6) | v;
		    j++;
		    if (j >= 4) {
		      out.write(i >> 16);
		      out.write(i >> 8);
		      out.write(i);
		      i = 0; j = 0;
		    }
		  }
		}
		switch (j) {
		case 3:
		  out.write(i >> 10);
		  out.write(i >> 2);
		  break;
		case 2:
		  out.write(i >> 4);
		  break;
		}
		return out.toByteArray();
		}

		public static String encodeUU(byte[] b, int off, int len) {
		int i = 0;
		StringBuffer s = new StringBuffer();
		while (len > 45) {
		  s.append('M');
		  for (int j = 0; j < 45; j += 3) {
		    i = ((b[off] & 0xFF) << 16) | ((b[off+1] & 0xFF) << 8) | (b[off+2] & 0xFF);
		    s.append((char)(' '+((i >> 18) & 0x3F)));
		    s.append((char)(' '+((i >> 12) & 0x3F)));
		    s.append((char)(' '+((i >> 6) & 0x3F)));
		    s.append((char)(' '+(i & 0x3F)));
		    off += 3;
		    len -= 3;
		  }
		  s.append('\n');
		}
		s.append((char)(' ' + len));
		while (len >= 3) {
		  i = ((b[off] & 0xFF) << 16) | ((b[off+1] & 0xFF) << 8) | (b[off+2] & 0xFF);
		  s.append((char)(' '+((i >> 18) & 0x3F)));
		  s.append((char)(' '+((i >> 12) & 0x3F)));
		  s.append((char)(' '+((i >> 6) & 0x3F)));
		  s.append((char)(' '+(i & 0x3F)));
		  off += 3;
		  len -= 3;
		}
		switch (len) {
		case 2:
		  i = ((b[off] & 0xFF) << 16) | ((b[off+1] & 0xFF) << 8);
		  s.append((char)(' '+((i >> 18) & 0x3F)));
		  s.append((char)(' '+((i >> 12) & 0x3F)));
		  s.append((char)(' '+((i >> 6) & 0x3F)));
		  break;
		case 1:
		  i = ((b[off] & 0xFF) << 16);
		  s.append((char)(' '+((i >> 18) & 0x3F)));
		  s.append((char)(' '+((i >> 12) & 0x3F)));
		  break;
		}
		return s.toString();
		}


}
