package cn.net.connor.nhjs.processcard;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.teamcenter.rac.aif.AIFDesktop;
import com.teamcenter.rac.aif.AbstractAIFApplication;
import com.teamcenter.rac.aif.kernel.AIFComponentContext;
import com.teamcenter.rac.aif.kernel.InterfaceAIFComponent;
import com.teamcenter.rac.kernel.TCComponent;
import com.teamcenter.rac.kernel.TCComponentBOMLine;
import com.teamcenter.rac.kernel.TCComponentBOMWindow;
import com.teamcenter.rac.kernel.TCComponentBOPWindowType;
import com.teamcenter.rac.kernel.TCComponentCfgAttachmentLine;
import com.teamcenter.rac.kernel.TCComponentItemRevision;
import com.teamcenter.rac.kernel.TCComponentUser;
import com.teamcenter.rac.kernel.TCException;
import com.teamcenter.rac.util.Registry;

import cn.net.connor.std.aifrcp.KOperation;
import cn.net.connor.std.aifrcp.util.KSWTProgressDialog;
import cn.net.connor.std.aifrcp.util.KUtil;
import cn.net.connor.std.word.word.KWordCategory;
import cn.net.connor.std.word.word.KWordUtil;

public class ExportOperation extends KOperation {

	protected static final Registry REG = Registry.getRegistry(ExportOperation.class);
	public static final String PREF_FILTER = "Connor_NHL_ProessCard";

	protected KSWTProgressDialog progressDialog;
	protected List<KWordCategory> kWordCategories = new ArrayList<>();
	protected List<FilterInfo> filterInfos = new ArrayList<>();
	protected List<TCComponentBOMWindow> windowToClose = new ArrayList<>();
	private TCComponentBOPWindowType bopWindowType;

	public ExportOperation(AbstractAIFApplication app, String prefNames) {
		super(app, REG.getString("op.Name"));
	}

	public static class FilterInfo {

		private String itemType_METarget;
		private String itemType_MEProcess;
		private String itemType_MEOP;
		private String itemName_MEOP;

		public FilterInfo(String itemType_METarget, String itemType_MEProcess, String itemType_MEOP, String itemName_MEOP) {
			super();
			this.itemType_METarget = itemType_METarget;
			this.itemType_MEProcess = itemType_MEProcess;
			this.itemType_MEOP = itemType_MEOP;
			this.itemName_MEOP = itemName_MEOP;
		}

		@Override
		public String toString() {
			if (KUtil.isEmpty(itemName_MEOP)) {
				return String.format("GY[%s][%s][%s]", itemType_METarget, itemType_MEProcess, itemName_MEOP);
			}
			return String.format("GX[%s][%s][%s]", itemType_METarget, itemType_MEOP, itemName_MEOP);
		}

	}

	@Override
	public boolean init() throws Exception {
		InterfaceAIFComponent[] targets = app.getTargetComponents();
		System.out.println("Select: " + Arrays.toString(targets));
		int targetCnt = KUtil.getLen(targets);
		if (targetCnt == 0) {
			return false;
		}
		bopWindowType = (TCComponentBOPWindowType) session.getTypeComponent("BOPWindow");
		String msg = REG.getString("init.Name") + "                                                                      ";
		this.progressDialog = new KSWTProgressDialog(AIFDesktop.getActiveDesktop().getShell(), "", msg, 0, false, true);
		progressDialog.openDialog();
		readFilterConfig();
		// 对选中的对象进行过滤
		targets = reloadTargetsByFilter(targets);
		System.out.println("After Filter: " + Arrays.toString(targets));
		targetCnt = KUtil.getLen(targets);
		if (targetCnt == 0) {
			throw new Exception(REG.getString("novalidtarget.Error"));
		}
		TCComponentUser owner = session.getUser();
		boolean isDba = owner.getLogicalProperty(TCComponentUser.PROP_IS_MEMBER_OF_DBA);
		System.out.println("Current User:" + owner + " DBA: " + isDba);
		List<TCComponent> unsupportedTargets = new ArrayList<>();
		for (int i = 0; i < targetCnt; i++) {
			TCComponent target = (TCComponent) targets[i];
			KWordCategory wordCategory = KWordCategory.parse(session, target);
			if (wordCategory != null) {
				TCComponent targetOwner;
				if (target instanceof TCComponentBOMLine) {
					targetOwner = ((TCComponentBOMLine) target).getItemRevision().getReferenceProperty("owning_user");
				} else if (target instanceof TCComponentCfgAttachmentLine) {
					targetOwner = target.getUnderlyingComponent().getReferenceProperty("owning_user");
				} else {
					targetOwner = target.getReferenceProperty("owning_user");
				}
				System.out.println("Check Owner [" + target + "]: " + targetOwner);
				if (!owner.equals(targetOwner) && !isDba) {
					System.out.println(">> Skip");
					// throw new TCException(REG.getString("notowner.Error"));
					continue;
				}
				this.kWordCategories.add(wordCategory);
			} else {
				System.out.println("No valid config: " + target);
				unsupportedTargets.add(target);
			}
		}
		if (unsupportedTargets.size() > 0) {
			throw new TCException(String.format(REG.getString("unsupportedtargets.Error1"), unsupportedTargets.toString()));
		}
		if (this.kWordCategories.size() == 0) {
			throw new TCException(REG.getString("novalidconfig.Error"));
		}
		return true;
	}

	private InterfaceAIFComponent[] reloadTargetsByFilter(InterfaceAIFComponent[] targets) throws Exception {
		List<InterfaceAIFComponent> res = new ArrayList<>();
		int len = KUtil.getLen(targets);
		for (int i = 0; i < len; i++) {
			InterfaceAIFComponent target = targets[i];
			if (target instanceof TCComponentBOMLine) {
				reloadTarget((TCComponentBOMLine) target, res, null);
			} else if(target instanceof TCComponentItemRevision){
				TCComponentItemRevision rev = (TCComponentItemRevision) target;
				TCComponentBOMWindow bopWindow = bopWindowType.create(null);
				this.windowToClose.add(bopWindow);
				TCComponentBOMLine bopLine = bopWindow.setWindowTopLine(rev.getItem(), rev, null, null);
				reloadTarget(bopLine, res, null);
			}else {
				System.out.println(">> Not BOMLine Or Revision: " + target);
			}
		}
		return res.toArray(new InterfaceAIFComponent[] {});
	}

	private void reloadTarget(TCComponentBOMLine target, List<InterfaceAIFComponent> res, List<String> matargetTypes) throws Exception {
		int filterCnt = this.filterInfos.size();
		String targetType = target.getStringProperty("bl_item_object_type");
		System.out.println("Filter > " + target + " >> " + targetType);
		if (res.contains(target)) {
			System.out.println(">> Skip Duplicate");
			return;
		}
		for (int i = 0; i < filterCnt; i++) {
			FilterInfo info = this.filterInfos.get(i);
			TCComponentItemRevision procRev = null;
			boolean cycleChildren = false;
			if (targetType.equals(info.itemType_MEProcess)) {
				System.out.println(">> Check: " + info);
				procRev = target.getItemRevision();
				cycleChildren = true;
			} else if (targetType.equals(info.itemType_MEOP)) {
				System.out.println(">> Check: " + info);
				String itemName = target.getStringProperty("bl_item_object_name");
				if (!itemName.equals(info.itemName_MEOP)) {
					System.out.println(">> Skip By Name [" + itemName + "]");
					continue;
				}
				if(matargetTypes==null) {
					for (TCComponentBOMLine pLine = target.parent(); pLine != null; pLine = pLine.parent()) {
						procRev = pLine.getItemRevision();
					}
					System.out.println("Proc: " + procRev);
				}
			} else {
				continue;
			}
			if(matargetTypes==null) {
				if (procRev == null) {
					System.out.println(">> Process Revision Not Found");
					continue;
				}
				matargetTypes = new ArrayList<>();
				TCComponent[] meTargets = procRev.getRelatedComponents("IMAN_METarget");
				System.out.println(">> METargets: " + Arrays.toString(meTargets));
				int len = KUtil.getLen(meTargets);
				for (int j = 0; j < len; j++) {
					TCComponent meTarget = meTargets[j];
					if (meTarget instanceof TCComponentItemRevision) {
						String meTargetType = ((TCComponentItemRevision) meTarget).getItem().getType();
						if(!matargetTypes.contains(meTargetType)) {
							matargetTypes.add(meTargetType);
						}
					}
				}
			}
			if (!matargetTypes.contains(info.itemType_METarget)) {
				System.out.println(">> Skip By METarget");
				continue;
			}
			if (!res.contains(target)) {
				res.add(target);
			}
			if (cycleChildren) {
				AIFComponentContext[] cc = target.getChildren();
				int childCnt = KUtil.getLen(cc);
				for (int j = 0; j < childCnt; j++) {
					TCComponentBOMLine cLine = (TCComponentBOMLine) cc[j].getComponent();
					reloadTarget(cLine, res, matargetTypes);
				}
			}
		}
	}

	private void readFilterConfig() throws Exception {
		String[] prefValues = KUtil.getPrefVals(session, PREF_FILTER);
		int len = KUtil.getLen(prefValues);
		for (int i = 0; i < len; i++) {
			String[] split = prefValues[i].split("=", -1);
			if (KUtil.getLen(split) != 4) {
				continue;
			}
			String itemType_METarget = split[0].trim();
			String typeName = split[1].trim();
			String itemName_MEOP = split[2].trim();
			boolean export = "Y".equalsIgnoreCase(split[3].trim());
			if (!export || KUtil.isEmpty(itemType_METarget) || KUtil.isEmpty(typeName)) {
				continue;
			}
			String itemType_MEProcess = null;
			String itemType_MEOP = null;
			if (KUtil.isEmpty(itemName_MEOP)) {
				itemType_MEProcess = typeName;
			} else {
				itemType_MEOP = typeName;
			}
			FilterInfo filterInfo = new FilterInfo(itemType_METarget, itemType_MEProcess, itemType_MEOP, itemName_MEOP);
			this.filterInfos.add(filterInfo);
		}
		System.out.println("FilterInfos: " + this.filterInfos);
		if (this.filterInfos.size() == 0) {
			throw new Exception("Preference Error: " + PREF_FILTER);
		}
	}

	@Override
	public void execute() throws Exception {
		int wordCnt = this.kWordCategories.size();
		KWordUtil.startWord();
		for (int i = 0; i < wordCnt; i++) {
			KWordCategory wordCate = this.kWordCategories.get(i);
			String msg;
			if (wordCnt == 1) {
				msg = String.format("%s %s", REG.getString("exporting"), wordCate.toString());
			} else {
				msg = String.format("( %d / %d ) %s %s", i + 1, wordCnt, REG.getString("exporting"), wordCate.toString());
			}
			progressDialog.updateMessage(msg);
			wordCate.export(session, progressDialog);
		}
		session.refreshComponentsByType("CfgBlAttachmentLine");
	}

	@Override
	public void clearCache() throws Exception {
		if (progressDialog != null) {
			progressDialog.closeDialog();
		}
		KWordUtil.closeWord();
		int wordCnt = this.kWordCategories.size();
		for (int i = 0; i < wordCnt; i++) {
			KWordCategory wordCate = this.kWordCategories.get(i);
			wordCate.clearCache();
		}
		for (TCComponentBOMWindow w : windowToClose) {
			try {
				w.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}
