package com.testingtech.tri.extfct;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.text.MessageFormat;

import org.etsi.mts.ttcn.part9.xmldiff.XmlDiff;
import org.etsi.ttcn.tci.BooleanValue;
import org.etsi.ttcn.tci.RecordOfValue;
import org.etsi.ttcn.tci.UniversalCharstringValue;

import com.testingtech.ttcn.annotation.ExternalFunction;
import com.testingtech.ttcn.tri.AnnotationsExternalFunctionPlugin;
import com.testingtech.util.FileUtil;

import de.tu_berlin.cs.uebb.muttcn.runtime.TestCaseError;

@ExternalFunction.Definitions(XmlDiffExtFctPlugin.class)
public class XmlDiffExtFctPlugin extends AnnotationsExternalFunctionPlugin {

	/**
	 * Lexical compare the charstring p_textToMatch with the contents of the reference XML file and returns true if they represent the same XML structure
	 * @param p_textToMatch text to be compared with the UTF-8 contents of the XML file
	 * @param p_referenceXmlFile the XML file
	 * @param p_xsdFileList the list of XSD files
	 * @param p_matchError the error result in case it did not match
	 * @param p_referenceTTCN3File the file of the TTCN-3 test module. This path is used to find the reference XML file relative to this path, by keeping the TTCN-3 code file system independent.
	 * @return true if p_textToMatch and the contents of p_referenceXmlFile represent the same XML structure
	 */
 	// external function matchFile(Raw p_textToMatch, File p_referenceXmlFile, FileList p_xsdFileList, out universal charstring p_matchError, File p_referenceTTCN3File := __FILE__) return boolean;
	@ExternalFunction(name = "matchFile")
	public BooleanValue matchFile(UniversalCharstringValue p_textToMatch,
			UniversalCharstringValue p_referenceXmlFile, RecordOfValue xsdFileList, UniversalCharstringValue p_matchError, UniversalCharstringValue p_referenceTTCN3File) {
        String stringToMatch = p_textToMatch.getString();
        File parentFolder = new File(p_referenceTTCN3File.getString()).getAbsoluteFile().getParentFile();
        String strReferenceXmlFile = p_referenceXmlFile.getString();
        strReferenceXmlFile = new File(parentFolder, strReferenceXmlFile).getAbsolutePath();
        
        String[] xsdFileArray = null;
        if (xsdFileList.getLength() > 0) {
            xsdFileArray = new String[xsdFileList.getLength()];
            for(int i = 0; i < xsdFileList.getLength(); i++) {
            	xsdFileArray[i] = ((UniversalCharstringValue)xsdFileList.getField(i)).getString();
            }
        }
        String description = "";
        boolean res = false;
        try {
            XmlDiff diff = new XmlDiff(strReferenceXmlFile, xsdFileArray, new String[]{parentFolder.getAbsolutePath()});
            StringBuilder sb = new StringBuilder();
            res = diff.diff(stringToMatch, sb);
            if (sb.length() > 0)
                description = sb.toString();
        } catch (Exception e) {
            description = e.getMessage();
        }
        if (!res && description == null)
            description = "Unspecified error";
        
        p_matchError.setString(description);
        
        return newBooleanValue(res);
    }
	
	/**
	 * Read a UTF-8 formated XML file from disc.
	 * @param p_referenceXmlFile the XML file
	 * @param p_referenceTTCN3File the file of the TTCN-3 test module. This path is used to find the reference XML file relative to this path, by keeping the TTCN-3 code file system independent.
	 * @return the UTF-8 contents of p_referenceXmlFile
	 */
	// external function readFile(universal charstring p_referenceXmlFile, universal charstring p_referenceTTCN3File := __FILE__) return universal charstring;
	@ExternalFunction(name = "readFile")
	public UniversalCharstringValue readFile(UniversalCharstringValue p_referenceXmlFile, UniversalCharstringValue p_referenceTTCN3File) {
	    FileInputStream in = null;
	    try {
		  File referenceTTCN3File = new File(p_referenceTTCN3File.getString());
		  String strReferenceXmlFile = p_referenceXmlFile.getString();
		  File file = new File(referenceTTCN3File.getAbsoluteFile().getParentFile(), strReferenceXmlFile);
	      in = new FileInputStream(file);
	      ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
	      FileUtil.copy(in, out);
	      return newUniversalCharstringValue(out.toString("UTF-8"));
	    } catch (Throwable e) {
	      throw new TestCaseError(new RuntimeException(MessageFormat.format("error while reading UTF-8 encoded file: {0} {1}", p_referenceXmlFile.getString(), e.toString()), e));
	    } finally {
	      try {
	        in.close();
	      } catch (Throwable e) {
	        // ignore exception
	      }
	    }
	}

}
