/* Copyright 2004 - M.A.Windhouwer - University of Amsterdam - LOT - TDS */

package sloot;

import com.ten60.netkernel.urii.*;
import org.ten60.netkernel.xml.xahelper.*;
import org.ten60.netkernel.xml.util.*;
import org.ten60.netkernel.xml.xda.*;
import org.ten60.netkernel.xml.representation.*;
import org.ten60.netkernel.layer1.meta.DependencyMeta;
import org.ten60.netkernel.layer1.representation.*;

import org.w3c.dom.*;

import java.io.*;

public class FixEncoding extends XAccessor
{

	public FixEncoding()
	{
		declareThreadSafe();
		declareArgument(OPERAND,true,false);
		declareArgument(OPERATOR,false,false);
	}

	protected IURRepresentation source(XAHelper aHelper) throws com.ten60.netkernel.util.NetKernelException
	{
		try {
			IXDAReadOnly operand = null;
			if (aHelper.hasOperand())
				operand = aHelper.getOperand().getXDA();
			
			if (operand == null) {
				System.err.println("ERR: fix encoding has no operand!");
				throw new com.ten60.netkernel.util.NetKernelException("fix encoding has no operand");
			}
			
			IXDAReadOnly operator = null;
			if (aHelper.hasOperator())
				operator = aHelper.getOperator().getXDA();
			
			Document result = null;
			Boolean fix = true;
			
			// is there a check?
			Boolean check          = false;
			String  check_xp       = null;
			String  check_val      = null;
			String  check_real_val = null;
			if (operator!=null)
			{	if (operator.isTrue("/encoding"))
				{	if (operator.isTrue("/encoding/check/xpath")) {
						check_xp = operator.getText("/encoding/check/xpath",true);
						if (operand.isTrue(check_xp))
							check_real_val = operand.getText(check_xp,true);
					}
					if ((check_real_val!=null) && !check_real_val.trim().equals(""))
					{	if (operator.isTrue("/encoding/check/value"))
							check_val = operator.getText("/encoding/check/value",true);
					}
					if ((check_real_val!=null) && (check_val!=null) && check_real_val.trim().equals(check_val.trim())) {
						System.err.println("WRN: the encoding check succeeds ["+check_real_val+"=="+check_val+"], so encoding don't needs fixing");
						fix = false;
					} else if ((check_real_val!=null) && (check_val!=null)) {
						System.err.println("WRN: the encoding check failed ["+check_real_val+"!="+check_val+"], so will try to fix and check the encoding");
						check = true;
					} else
						System.err.println("WRN: no encoding check, but will try to fix the encoding");
				}
			}

			// fix encoding
			if (fix) {
				// the source encoding, i.e. in what encoding has the document been originally send
				String src_encoding = "";
				if (operator!=null)
				{	if (operator.isTrue("/encoding"))
					{	if (operator.isTrue("/encoding/source/xpath")) {
							String xp = operator.getText("/encoding/source/xpath",true);
							if (operand.isTrue(xp))
								src_encoding = operand.getText(xp,true);
						}
						if (src_encoding.trim().equals(""))
						{	if (operator.isTrue("/encoding/source/default"))
								src_encoding = operator.getText("/encoding/source/default",true);
							else if (operator.isTrue("/encoding/source"))
								src_encoding = operator.getText("/encoding/source",true);
						}
					}
				}
				if (src_encoding.trim().equals(""))
					src_encoding = "ISO-8859-1"; // the Jetty default
	
				// the destination encoding, i.e. in what encoding do we want to have it
				String dest_encoding = "";
				if (operator!=null)
				{	if (operator.isTrue("/encoding"))
					{	if (operator.isTrue("/encoding/destination/xpath")) {
							String xp = operator.getText("/encoding/destination/xpath",true);
							if (operand.isTrue(xp))
								dest_encoding = operand.getText(xp,true);
						}
						if (dest_encoding.trim().equals(""))
						{	if (operator.isTrue("/encoding/destination/default"))
								dest_encoding = operator.getText("/encoding/destination/default",true);
							else if (operator.isTrue("/encoding/destination"))
								dest_encoding = operator.getText("/encoding/destination",true);
						}
					}
				}
				if (dest_encoding.trim().equals(""))
					dest_encoding = "UTF-8"; // the NK default
				
				System.err.println("DBG: fix encoding source["+src_encoding+"] destination["+dest_encoding+"]");
				
				if (dest_encoding.equalsIgnoreCase(src_encoding))
					result = (Document)XMLUtils.getInstance().safeDeepClone(aHelper.getOperand().getReadOnlyDocument());
				else {
					StringWriter sw = new StringWriter();
					operand.serialize(sw,false);
	
					String src = sw.toString();

					//System.err.println("DBG: fix encoding ["+src_encoding+"] source["+src+"]");

					String dst = new String(src.getBytes(src_encoding),dest_encoding);
	
					//System.err.println("DBG: fix encoding ["+dest_encoding+"] destination["+dst+"]");

					Document doc = (Document)XMLUtils.parse(new StringReader(dst));
					
					if (check) {
						// inspect the result
						DOMXDA xda = new DOMXDA(doc,false);
						check_real_val = xda.getText(check_xp,true);
						if ((check_real_val!=null) && (check_val!=null) && check_real_val.trim().equals(check_val.trim())) {
							// accept the result
							result = doc;
						} else
							System.err.println("ERR: the encoding fix failed, the encoding check still fails ["+check_real_val+"!="+check_val+"]!");
					} else {
						// just accept the result
						result = doc;
					}
				}
			}
			
			// nothing happened, return the input
			if (result == null)
				result = (Document)XMLUtils.getInstance().safeDeepClone(aHelper.getOperand().getReadOnlyDocument());

			DOMXDA    resXDA = new DOMXDA(result,false);
			IURMeta   meta   = aHelper.getDependencyMeta("text/xml",8);
			IURAspect aspect = new DOMXDAAspect(resXDA);

			return new MonoRepresentationImpl(meta,aspect);
		} catch(Exception e) {
			System.err.println("ERR: fix encoding failed:\n"+e);
			//e.printStackTrace(System.err);
			com.ten60.netkernel.util.NetKernelException ne = new com.ten60.netkernel.util.NetKernelException("fix encoding failed");
			ne.addCause(e);
			throw ne;
		}
	}
}
