/* $Id: CreateXMLElementVisitor.java 521 2012-07-12 16:49:07Z shayashi $ */
package smart_gs.logical.visitor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import reasoning_web.logical.Connection;
import reasoning_web.logical.inter_face.RWElement;
import smart_gs.connection.LinkChecker;
import smart_gs.debugprint.Debugprint;
import smart_gs.logical.GSResource;
import smart_gs.logical.ResourceBasket;
import smart_gs.logical.URIObject;
import smart_gs.logical.UsersNote;
import smart_gs.logical.UsersNoteDirectory;
import smart_gs.logical.Region;
import smart_gs.logical.Spread;
import smart_gs.logical.SpreadDirectory;
import smart_gs.logical.IDAT;
import smart_gs.logical.StandardTextDocument;
import smart_gs.logical.TextSegment;
import smart_gs.logical.Zombie;
import smart_gs.reasoning_web.logical.GSExplanatoryNote;
import smart_gs.reasoning_web.logical.GS_RWElement;
import smart_gs.reasoning_web.logical.GS_RWRepository;
import smart_gs.util.GSStandardPath;

public class CreateXMLElementVisitor implements Visitor {

	private Document document;
	private Stack<Element> elements;

	public CreateXMLElementVisitor(Document document) {
		this.document = document;
		this.elements = new Stack<Element>();
	}

	public void visit(Spread spread) {
		Element element = document.createElement("spread");
		element.setAttribute(GSResource.NAME, spread.getName());
		element.setAttribute(GSResource.URI, spread.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, spread.getOriginalURI());
		element.setAttribute(GSResource.OLD_VERSION_URI, spread.getOldVersionURI());
		element.setAttribute(GSResource.VERSION, spread.getVersion());

		element.setAttribute("firstIDATName", spread.getFirstIDATNameToSave());
		element.setAttribute("secondIDATName", spread.getSecondIDATNameToSave());
		element.setAttribute("thirdIDATName", spread.getThirdIDATNameToSave());		

		String filepath = spread.getFile().getPath();
		
//		TODO 20110910 shayashi
		element.setAttribute("filename", GSStandardPath.standardizeFileName(filepath));

		List<Region> regions = spread.getRegions();

		// ADD northgrid
		// リンク切れ判定
		{
			HashMap<String,String> linkMarge = new HashMap<String,String>();
			HashMap<String,String> linkMap = new HashMap<String,String>();
			for (int i = 0; i < regions.size(); i++) {
				String baseURI = regions.get(i).getBaseURI();
				String uri = regions.get(i).getURI();
				if(baseURI != null){
					linkMarge.put(baseURI, baseURI);
				}
				if(uri != null){
					linkMap.put(uri, uri);
				}
			}
			// Region内のリンクリスト取得
			Iterator<String> itr = linkMarge.keySet().iterator();
			while(itr.hasNext()){
				String baseURI = itr.next();
				ArrayList<Connection> deleteConnection = new ArrayList<Connection>();
				List<Connection> connectList = GS_RWRepository.getInstance().getConnections();
				for(int i=0;i<connectList.size();i++){
					Connection connection = connectList.get(i);
					RWElement sourceRWElement = connection.getSourcePointer().getRwElement();
					if(sourceRWElement.getTypeString().equals("zombie")){
						deleteConnection.add(connection);
						continue;
					} else if(sourceRWElement instanceof GS_RWElement){
						if(((GS_RWElement)sourceRWElement).getURI().startsWith(baseURI)){
							if(!linkMap.containsKey(((GS_RWElement)sourceRWElement).getURI())){
								deleteConnection.add(connection);
								continue;
							}
						}
					}
					RWElement targetRWElement = connection.getTargetPointer().getRwElement();
					if(targetRWElement.getTypeString().equals("zombie")){
						deleteConnection.add(connection);
						continue;
					} else if(targetRWElement instanceof GS_RWElement){
						if(((GS_RWElement)targetRWElement).getURI().startsWith(baseURI)){
							if(!linkMap.containsKey(((GS_RWElement)targetRWElement).getURI())){
								deleteConnection.add(connection);
								continue;
							}
						}
					}
				}
				if(deleteConnection.size() != 0){
					for(int i=0;i<deleteConnection.size();i++){
						Connection connection = deleteConnection.get(i);
						GS_RWRepository.getInstance().removeConnection(connection);
					}
				}
	
			}
		}
		// ADD northgrid

		for (int i = 0; i < regions.size(); i++) {
			Region reg = regions.get(i);
			if (! reg.isTemporary()) {
				regions.get(i).accept(this);
				element.appendChild(this.elements.pop());
			}
		}

		spread.getFirstIDAT().accept(this);
		element.appendChild(this.elements.pop());
		spread.getSecondIDAT().accept(this);
		element.appendChild(this.elements.pop());
		spread.getThirdIDAT().accept(this);
		element.appendChild(this.elements.pop());

		elements.push(element);
	}

	public void visit(Region region) {
		Element element = document.createElement("region");
		element.setAttribute(GSResource.NAME, region.getName());
		element.setAttribute(GSResource.URI, region.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, region.getOriginalURI());
		element.setAttribute(GSResource.OLD_VERSION_URI, region.getOldVersionURI());
		element.setAttribute(GSResource.VERSION, region.getVersion());
		// kazuhiro kobayashi
		element.setAttribute("protection", region.isProtected());
		element.appendChild(region.getView().createXMLElement(document));
		this.elements.push(element);
	}

	public void visit(IDAT doc) {
		Element element = this.document.createElement("spreadDocument");
		element.setAttribute("type", doc.getType() + "");
		element.setAttribute(GSResource.URI, doc.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, doc.getOriginalURI());
		element.setAttribute(GSResource.OLD_VERSION_URI, doc.getOldVersionURI());
		element.setAttribute(GSResource.VERSION, doc.getVersion());

		element.setAttribute("source", doc.getSource());

		//----- NorthGrid
		// リンク切れを判定
		ArrayList<Integer> deleteIdList = new ArrayList<Integer>();
		{
			HashMap<String, Integer> linkMap = new HashMap<String, Integer>();;
			try{
				String source = doc.getSource();
				source = source.substring(source.indexOf("<xml>") + "<xml>".length(),source.lastIndexOf("</xml>"));
				LinkChecker linkChecker = new LinkChecker();
				linkChecker.parse(source);
				linkMap = linkChecker.getLinkMap();
			}catch(Exception e){}
			// リンクを判定
			List<TextSegment> segments = doc.getSegments();
			for (int i = 0; i < segments.size(); i++) {
				int id = segments.get(i).getId();
				if(!linkMap.containsKey(String.valueOf(id))){
					deleteIdList.add(new Integer(id));
				}
			}
		}
		// リンクを削除
		ArrayList<String> deleteUrlList = new ArrayList<String>();
		if(deleteIdList.size() != 0){
			for(int i=0;i<deleteIdList.size();i++){
				Integer id = deleteIdList.get(i);
				TextSegment textSegment = doc.getSegmentByID(id.intValue());
				if(textSegment != null){
					deleteUrlList.add(textSegment.getURI());
					doc.removeTextSegment(id.intValue());
				}
			}
		}
		if(deleteUrlList.size() != 0){
			ArrayList<Connection> deleteConnection = new ArrayList<Connection>();
			List<Connection> connectList = GS_RWRepository.getInstance().getConnections();
			for(int i=0;i<connectList.size();i++){
				Connection connection = connectList.get(i);
				RWElement sourceRWElement = connection.getSourcePointer().getRwElement();
				if(sourceRWElement instanceof GS_RWElement){
					for(int j=0;j<deleteUrlList.size();j++){
						String url = deleteUrlList.get(j);
						if(url != null){
							if(url.equals(((GS_RWElement)sourceRWElement).getURI())){
								deleteConnection.add(connection);
								break;
							}
						}
					}
				}
				RWElement targetRWElement = connection.getTargetPointer().getRwElement();
				if(targetRWElement instanceof GS_RWElement){
					for(int j=0;j<deleteUrlList.size();j++){
						String url = deleteUrlList.get(j);
						if(url != null){
							if(url.equals(((GS_RWElement)targetRWElement).getURI())){
								deleteConnection.add(connection);
								break;
							}
						}
					}
				}
			}
			if(deleteConnection.size() != 0){
				for(int i=0;i<deleteConnection.size();i++){
					Connection connection = deleteConnection.get(i);
					GS_RWRepository.getInstance().removeConnection(connection);
				}
			}
		}
		//----- NorthGrid

		List<TextSegment> segments = doc.getSegments();
		for (int i = 0; i < segments.size(); i++) {
			segments.get(i).accept(this);
			element.appendChild(this.elements.pop());
		}
		this.elements.push(element);
	}

	public void visit(TextSegment segment) {
		Element element = this.document.createElement("segment");
		element.setAttribute(GSResource.ID, segment.getId() + "");
		element.setAttribute("tagname", segment.getTagName());
		element.setAttribute(GSResource.URI, segment.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, segment.getOriginalURI());
		element.setAttribute(GSResource.VERSION, segment.getVersion());

		this.elements.push(element);
	}

	public void visit(SpreadDirectory directory) {
		Element element = this.document.createElement("directory");
		element.setAttribute(GSResource.NAME, directory.getName());
		element.setAttribute(GSResource.URI, directory.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, directory.getOriginalURI());
		element.setAttribute(GSResource.OLD_VERSION_URI, directory.getOldVersionURI());
		element.setAttribute(GSResource.VERSION, directory.getVersion());

		//2007/12/1 kazuhiro kobayashi
		String dirpath = directory.getFile().getPath();
//		shayashi 2011.05.26
		element.setAttribute("filename", GSStandardPath.standardizeDirName(dirpath));

		List<GSResource> resources = directory.getResources();
		for (int i = 0; i < resources.size(); i++) {
			resources.get(i).accept(this);
			element.appendChild(this.elements.pop());
		}
		this.elements.push(element);
	}

	// 20070923 shimizu wrote;
	public void visit(UsersNote usersNote) {
		Element element = this.document.createElement("usersNote");
		element.setAttribute("source", usersNote.getSource());
		element.setAttribute(GSResource.NAME, usersNote.getName());
		element.setAttribute(GSResource.ID, usersNote.getId() + "");
	//20071212 shimizu wrote;
		element.setAttribute(GSResource.URI, usersNote.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, usersNote.getOriginalURI());
		element.setAttribute(GSResource.OLD_VERSION_URI, usersNote.getOldVersionURI());
		element.setAttribute(GSResource.VERSION, usersNote.getVersion());

		List<TextSegment> segments = usersNote.getSegments();
		for (int i = 0; i < segments.size(); i++) {
			segments.get(i).accept(this);
			element.appendChild(this.elements.pop());
		}
		this.elements.push(element);
	}
	
	// 2011.04.19 shayashi
	@Override
	public void visit(UsersNoteDirectory usersNoteDirectory) {
		Element element = this.document.createElement("usersNoteDirectory");
		element.setAttribute(GSResource.NAME, usersNoteDirectory.getName());
		element.setAttribute(GSResource.URI, usersNoteDirectory.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, usersNoteDirectory.getOriginalURI());
		element.setAttribute(GSResource.OLD_VERSION_URI, usersNoteDirectory.getOldVersionURI());
		element.setAttribute(GSResource.VERSION, usersNoteDirectory.getVersion());

		List<GSResource> resources = usersNoteDirectory.getResources();
		for (int i = 0; i < resources.size(); i++) {
			resources.get(i).accept(this);
			element.appendChild(this.elements.pop());
		}
		this.elements.push(element);
	}

	public void visit(StandardTextDocument textDocument) {
		Element element = this.document.createElement("standardDocument");
		element.setAttribute(GSResource.URI, textDocument.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, textDocument.getOriginalURI());
		element.setAttribute(GSResource.OLD_VERSION_URI, textDocument.getOldVersionURI());
		element.setAttribute(GSResource.VERSION, textDocument.getVersion());
		element.setAttribute(GSResource.NAME, textDocument.getName());
		element.setAttribute("source", textDocument.getSource());
		List<TextSegment> segments = textDocument.getSegments();
		for (int i = 0; i < segments.size(); i++) {
			segments.get(i).accept(this);
			element.appendChild(this.elements.pop());

		}
		this.elements.push(element);
	}

	public void visit(GSExplanatoryNote note) {
		Element element = this.document.createElement("explanatory");
		element.setAttribute("source", note.getSource());
		element.setAttribute(GSResource.NAME, note.getName());
		element.setAttribute(GSResource.ID, note.getId() + "");
		element.setAttribute(GSResource.URI, note.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, note.getOriginalURI());
		element.setAttribute(GSResource.OLD_VERSION_URI, note.getOldVersionURI());
		element.setAttribute(GSResource.VERSION, note.getVersion());

		List<TextSegment> segments = note.getSegments();
		for (int i = 0; i < segments.size(); i++) {
			segments.get(i).accept(this);
			element.appendChild(this.elements.pop());
		}
		this.elements.push(element);

	}

	public Element getLastElement() {
		return this.elements.pop();
	}
	

	@Override
	public void visit(Zombie zombie) {
		Element element = this.document.createElement(URIObject.ZOMBIE);
		element.setAttribute("deadURI", zombie.getDeadURI());
		element.setAttribute(GSResource.URI, zombie.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, zombie.getOriginalURI());
		element.setAttribute(GSResource.VERSION, zombie.getVersion());

		this.elements.push(element);		
	}

	public void visit(ResourceBasket resourceBasket) {
		if (!resourceBasket.toBeSaved()) {
			return;
		}
		Element element = this.document.createElement(URIObject.RESOURCE_BASKET);
		element.setAttribute(GSResource.URI, resourceBasket.getURI());
		element.setAttribute(GSResource.ORIGINAL_URI, resourceBasket.getOriginalURI());
		element.setAttribute(GSResource.VERSION, resourceBasket.getVersion());
		element.setAttribute(GSResource.NAME, resourceBasket.getName());
		for (int i = 0; i < resourceBasket.getResources().size(); i++) {
			Element elem = this.document.createElement(ResourceBasket.RESOURCE_URI);
			elem.setTextContent(resourceBasket.getResources().get(i).getURI());
			element.appendChild(elem);
		}
		this.elements.push(element);		
	}
}