package com.pack.service;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.jdom.Element;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.pack.MainServer;
import com.pack.Utils;
import com.taurus.core.entity.ITArray;
import com.taurus.core.entity.ITObject;
import com.taurus.core.entity.TArray;
import com.taurus.core.entity.TObject;
import com.taurus.core.plugin.redis.Redis;
import com.taurus.core.routes.ActionKey;
import com.taurus.core.util.Logger;
import com.taurus.core.util.StringUtil;
import com.taurus.web.Controller;

import redis.clients.jedis.Jedis;

public class PackUtilService extends Controller{
	private static final Object lock = new Object();
	
	static void exeCmd(String cmdCode,Logger log) {
        BufferedReader br = null;
        try {
            Process p = Runtime.getRuntime().exec(cmdCode);
            br = new BufferedReader(new InputStreamReader(p.getInputStream(), "GBK"));
            String line;
            while ((line = br.readLine()) != null) {
            	log.info(line);
            }
            p.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
	
	private void asynBuild(String threadName,String cmd,String os,ITArray arr) {
		Thread thread = new Thread(new Runnable() {
			
			@Override
			public void run() {
				logger.info("building "+os+"...");
				exeCmd(cmd,logger);
				for (int i = 0; i < arr.size(); i++) {
					ITObject obj = arr.getTObject(i);
					String tem_ver = obj.getUtfString("version");
					String bundle = obj.getUtfString("bundle");
					bundle = bundle.replaceAll("\\.", "/");
					String obj_name = "/"+bundle+"/asset_pack"+tem_ver+".bytes";
					logger.info(obj.getUtfString("name")+"["+tem_ver + "] pack to oss...");
					try {
						String path = MainServer.packConfig.getChildTextTrim("temp-pack-path");
						Utils.uploadOssPack(os+obj_name, path);
					} catch (Exception e) {
						logger.error(e);
						buildCount ++;
						throw new RuntimeException(e);
					}
					logger.info(obj.getUtfString("name")+"["+tem_ver + "] upload oss ok!");
				}
				
				buildCount ++;
			}
		});
		thread.setName(threadName + "-" + os);
		thread.start();
		
	}
	private volatile int buildCount;
	@ActionKey(value = "pack_extend")
	public final void packExtend() throws Exception {
		ITObject params = this.getParams();
		ITArray list = params.getTArray("list");
		if(list.size()==0) {
			this.sendResponse(0, null);
			return;
		}
		String threadName = this.getRemoteAddr()+"(extend)";
		Thread.currentThread().setName(threadName);
		synchronized(lock) {
			buildCount = 0;
			int svr_type = params.getInt("svr_type");
			List<Map<String,String>> redis_list = new ArrayList<>();
			for(int i=0;i<list.size();++i) {
				redis_list.add(new HashMap<>());
			}
			logger.info("start build pack ...");
			
			String svr = Utils.svr_list[svr_type];
			Jedis jedis1 = Redis.use(svr+"_db1").getJedis();
			try {
				ITArray arr = TArray.newInstance();
				for(int i=0;i<list.size();++i) {
					int game_id = list.getInt(i);
					ITObject gameObj = Utils.getGameData(jedis1, game_id,true);
					Map<String,String> redis_map = redis_list.get(i);
					String ver = gameObj.getUtfString("version");
					redis_map.put("version", ver);
					arr.addTObject(gameObj);
				}
				String temp_path = MainServer.packConfig.getChildTextTrim("temp-pack-path");
				ITObject tem = TObject.newInstance();
				tem.putTArray("data", arr);
				tem.putUtfString("hotpath", temp_path);
				String data_path = MainServer.packConfig.getChildTextTrim("data-path");
				FileOutputStream fos = new FileOutputStream(data_path); 
				fos.write(StringUtil.getBytes(tem.toJson()));
				fos.close();
				String cmd_params = " \""+data_path+"\"";
				String bat_path = MainServer.packConfig.getChildTextTrim("android-path")+"build-extend.bat";
				String cmd = bat_path + cmd_params + " \"android\"";
				asynBuild(threadName,cmd,"Android",arr);	
				bat_path = MainServer.packConfig.getChildTextTrim("ios-path")+"build-extend.bat";
				cmd = bat_path + cmd_params + " \"ios\"";
				asynBuild(threadName,cmd,"iOS",arr);
				bat_path = MainServer.packConfig.getChildTextTrim("win-path")+"build-extend.bat";
				cmd = bat_path + cmd_params + " \"win\"";
				asynBuild(threadName,cmd,"Win",arr);

				while(buildCount < 3) {
					Thread.sleep(100);
				}
				
				for (int i = 0; i < redis_list.size(); i++) {
					Map<String, String> map = redis_list.get(i);
					int game_id = list.getInt(i);
					String key = "game:"+game_id;
					jedis1.hmset(key, map);
					jedis1.hincrBy(key, "cache_ver", 1);
				}
			}finally {
				jedis1.close();
			}
		}
		
		
	}
	
	
	@SuppressWarnings("unchecked")
	@ActionKey(value = "pack_base")
	public final void packBase() throws Exception {
		ITObject params = this.getParams();
		ITArray list = params.getTArray("list");
		if(list.size()==0) {
			this.sendResponse(0, null);
			return;
		}
		String threadName = this.getRemoteAddr()+"(base)";
		Thread.currentThread().setName(threadName);
		synchronized (lock) {
			buildCount = 0;
			logger.info("start build pack ...");
			List<BaseConfigData> config_list = new ArrayList<>();
			Element init_json_list = MainServer.packConfig.getChild("init-json-list");
			@SuppressWarnings("rawtypes")
			List base_config = init_json_list.getChildren();
			for (int i = 0; i < base_config.size(); i++) {
				Element elem = (Element)base_config.get(i);
				String url = elem.getChildTextTrim("url");
				String oss_key = elem.getChildTextTrim("oss_key");
				String init_json = elem.getChildTextTrim("init_json");
				BaseConfigData bcd = new BaseConfigData();
				byte[] bytes = Utils.httpGet(url);
				if(bytes==null)continue;
				String str = StringUtil.getString(bytes);
				bcd.init_config_map = JSON.parseObject(str,LinkedHashMap.class, Feature.OrderedField);
				Map<String,Object> obj = (Map<String, Object>) bcd.init_config_map.get("Android");
				bcd.old_ver = (String) obj.get("version");
				String v_tem[] = bcd.old_ver.split("\\.");
				bcd.new_ver = v_tem[0]+"."+v_tem[1]+"."+(Integer.parseInt(v_tem[2])+1);
				bcd.oss_key = oss_key;
				bcd.init_json = init_json;
				config_list.add(bcd);
			}
			String ver = config_list.get(0).old_ver;
			String config_url = MainServer.packConfig.getChildTextTrim("config-url");
			byte[] bytes = Utils.httpGet(config_url+"asset_config"+ver+".json");
			if(bytes==null)return;
			String str = StringUtil.getString(bytes);
			ITArray config_arr = TArray.newFromJsonData(str);
			ITArray arr = TArray.newInstance();
			for(int i=0;i<list.size();++i) {
				String name = list.getUtfString(i);
				for(int k=0;k<config_arr.size();++k) {
					 ITObject obj = config_arr.getTObject(k);
					 if(obj.getUtfString("name").equals(name)) {
						 String tem_ver = obj.getUtfString("ver");
						 String tem[] = tem_ver.split("\\.");
						 tem_ver = tem[0]+"."+tem[1]+"."+(Integer.parseInt(tem[2])+1);
						 obj.putUtfString("ver", tem_ver);
						 arr.addTObject(obj);
						 break;
					 }
				}
			}
			String temp_path = MainServer.packConfig.getChildTextTrim("temp-pack-path");
			ITObject tem = TObject.newInstance();
			tem.putTArray("data", arr);
			tem.putUtfString("hotpath", temp_path);
			String data_path = MainServer.packConfig.getChildTextTrim("data-path");
			FileOutputStream fos = new FileOutputStream(data_path); 
			fos.write(StringUtil.getBytes(tem.toJson()));
			fos.close();
			for (int i = 0; i < arr.size(); i++) {
				ITObject obj = arr.getTObject(i);
				String bundle = "base/" + obj.getUtfString("name");
				obj.putUtfString("version", obj.getUtfString("ver"));
				obj.putUtfString("bundle", bundle);
			}
			String cmd_params = " \""+data_path+"\"";
			String bat_path = MainServer.packConfig.getChildTextTrim("android-path")+"build-base.bat";
			String cmd = bat_path + cmd_params + " \"android\"";
			asynBuild(threadName,cmd,"Android",arr);	
			bat_path = MainServer.packConfig.getChildTextTrim("ios-path")+"build-base.bat";
			cmd = bat_path + cmd_params + " \"ios\"";
			asynBuild(threadName,cmd,"iOS",arr);
			bat_path = MainServer.packConfig.getChildTextTrim("win-path")+"build-base.bat";
			cmd = bat_path + cmd_params + " \"win\"";
			asynBuild(threadName,cmd,"Win",arr);
			
			while(buildCount < 3) {
				Thread.sleep(100);
			}
			
			for (BaseConfigData bcd : config_list) {
				bcd.config_arr =config_arr;
				bcd.writeNewVer();
			}
		}
	}
	
	private static final class BaseConfigData{
		public Map<String,Object> init_config_map;
		
		public String old_ver;
		
		public String new_ver;
		
		public ITArray config_arr;
		public String init_json;

		public String oss_key;
		
		@SuppressWarnings("unchecked")
		public void writeNewVer() throws Exception {
			List<Object> object= JSON.parseObject(config_arr.toJson(),ArrayList.class,Feature.OrderedField);
			String json_str = JSON.toJSONString(object, SerializerFeature.PrettyFormat);
			String config_path = "/config/asset_config"+new_ver+".json";
			byte[] config_bytes = StringUtil.getBytes(json_str);
			List<?> list = MainServer.ossListConfig.getChildren();
			for (Object o : list) {
				Element ossConfig = (Element)o;
				Utils.uploadOss(ossConfig,MainServer.probjectName+config_path,config_bytes);
			}
			
			Map<String,Object> obj = (Map<String, Object>) init_config_map.get("Android");
			obj.put("version", new_ver);
			obj = (Map<String, Object>) init_config_map.get("iOS");
			obj.put("version", new_ver);
			obj = (Map<String, Object>) init_config_map.get("Win");
			obj.put("version", new_ver);
			json_str = JSON.toJSONString(init_config_map, SerializerFeature.PrettyFormat);
			
			Element ossConfig = MainServer.ossListConfig.getChild(oss_key);
			Utils.uploadOss(ossConfig,"configure/test1/"+init_json,StringUtil.getBytes(json_str));
		}
	}
}
