/* **********************************************************************
 * source:    TestScd
 * package:   com.me.my.scd.test
 * author:    sisjo
 ************************************************************************/
package com.me.my.scd.test;

import com.me.my.xml.toys.MyMarshallingHelper;
import com.me.my.scd.mappings.*;

import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBContext;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.List;
import java.util.ArrayList;
import java.io.InputStream;
import java.io.File;
import java.io.OutputStream;
import java.io.FileOutputStream;

/* ************
* class: TestScd
* <p>
* This is a class to ...
*/
public final class TestScd {
  static private final boolean        B_UseSchemas = false;
  static private final String         S_TestPkg = "com.me.my.scd.test";
  static private final String         S_TestXmlInput  = "TestJaxb.xml";
  static private final String         S_SchemaPkg = "com.me.my.schemas";
  static private final String         S_SchemaBase = "MyBase.xsd";
  static private final String         S_SchemaExtn = "MyExtended.xsd";
  static private final Logger         myLogger = Logger.getAnonymousLogger();
  static private final com.me.my.scd.mappings.ObjectFactory
                                      myFpaFac = new com.me.my.scd.mappings.ObjectFactory();

  private Marshaller          writer = null;
  private Unmarshaller        reader = null;
  private MyMarshallingHelper helper = null;
  private JAXBContext         context = null;
  private boolean             valid = false;
  private Throwable           failure = null;

  /************
   * create a reader-writer
   * @param wrkClz
   * @param afis
   */
  private TestScd(Class wrkClz, InputStream[] afis) {
    try {
      context = JAXBContext.newInstance(wrkClz);
      helper = new MyMarshallingHelper(null, true, myLogger);
      reader = context.createUnmarshaller();
      writer = context.createMarshaller();
      valid  = true;
      if (B_UseSchemas) {
        // set the schema stuff
        helper.getSchemaHelper().addSchema("MyTests", afis);
      }
    }
    catch(Throwable th) {
      failure = th;
      valid = false;
    }
  }

  /************
   * read the test xml
   * @throws Exception
   */
  private void readTest() throws Exception {
    // try to access the test data in the classpath [jar]
    String sTest = S_TestPkg.replace('.', '/')  + "/" + S_TestXmlInput; // Input or Output
    InputStream fis = ClassLoader.getSystemResourceAsStream(sTest);
    if (fis == null) {
      throw new IllegalArgumentException("Failed to locate source: " + sTest);
    }
    helper.setupUnmarshaller(reader, B_UseSchemas, true, true, "FutureProof", null);
    Object obj = reader.unmarshal(fis);
    if (obj instanceof MyBaseItem) {
      MyBaseItem bi = (MyBaseItem)obj;
    }
    else if (obj instanceof MyExtendedItem) {
      MyExtendedItem xi = (MyExtendedItem)obj;
    }
    else {
      throw new IllegalArgumentException("Failed to load source: " + ((obj == null) ? "null" : obj.getClass().getName()));
    }
  }

  private void writeTest() throws Exception {
    boolean bWriteBase = true;
    boolean bWriteExtn = true;
    if (bWriteBase) {
      writeBase();
    }
    if (bWriteExtn) {
      writeExtn();
    }
  }

  private void writeBase() throws Exception {
    // data
    MyBaseItem bi = myFpaFac.createMyBaseItem();
    bi.setTheItemName("Base Item Name");
    bi.getContacts().addAll(baseContacts());
    // work
    writeItem(bi, "MyBase");
  }

  private void writeExtn() throws Exception {
    // data
    MyExtendedItem xi = myFpaFac.createMyExtendedItem();
    xi.setTheExtendedItemName("Extended Item Name");
    xi.getCorrespondents().addAll(extnCorrespondents());
    xi.getContacts().addAll(extnContacts());
    // work
    writeItem(xi, "MyExtn");
  }

  private void writeItem(Object item, String sWhat) throws Exception {
    // work
    String sOut = "testOutScd-" + sWhat + ".xml";
    File root = new File(System.getProperty("user.dir", ".\\")).getCanonicalFile();
    File outx = new File(root, sOut);
    OutputStream os = new FileOutputStream(outx);
    // marshal
    helper.setupMarshaller(writer, true, true, true, true, true, "ISO-8859-1", "MyTests", null);
    writer.marshal(item, os);
  }

  private List<MyBaseItem.Contacts> baseContacts() {
    List<MyBaseItem.Contacts> lc = new ArrayList<MyBaseItem.Contacts>();
    for (int iC=0; iC < 3; iC++) {
      MyBaseItem.Contacts cc = myFpaFac.createMyBaseItemContacts();
      cc.setForename("Fore-" + iC);
      cc.setSurname("Sur-" + iC);
      cc.setTitle("Instigator No." + iC);
      cc.getWorkAddress().add(address("Base", iC));
      cc.setHomeEmail(email("home", "base", iC));
      //
      lc.add(cc);
    }
    return lc;
  }

  private List<MyExtendedItem.Contacts> extnContacts() {
    List<MyExtendedItem.Contacts> lc = new ArrayList<MyExtendedItem.Contacts>();
    for (int iC=0; iC < 3; iC++) {
      MyExtendedItem.Contacts cc = myFpaFac.createMyExtendedItemContacts();
      cc.setForename("Fore-" + iC);
      cc.setSurname("Sur-" + iC);
      cc.setTitle("Instigator No." + iC);
      cc.getWorkAddress().add(address("Extn", iC));
      cc.setWorkEmail(email("work", "extn", iC));
      //
      lc.add(cc);
    }
    return lc;
  }

  private List<MyExtendedItem.Correspondents> extnCorrespondents() {
    List<MyExtendedItem.Correspondents> lc = new ArrayList<MyExtendedItem.Correspondents>();
    for (int iC=0; iC < 3; iC++) {
      MyExtendedItem.Correspondents cc = myFpaFac.createMyExtendedItemCorrespondents();
      cc.setForename("Fore-" + iC);
      cc.setSurname("Sur-" + iC);
      cc.setTitle("Instigator No." + iC);
      cc.getWorkAddress().add(address("Base", iC));
      cc.setHomeEmail(email("home", "base", iC));
      //
      lc.add(cc);
    }
    return lc;
  }

  private MyAddressType address(String sScope, int inst) {
    MyAddressType aa = myFpaFac.createMyAddressType();
    aa.setAddress("10" + inst + " Happy " + sScope + " Drive");
    aa.setTown("Dumbarton");
    aa.setPostcode("10234");
    return aa;
  }

  private MyEmailType email(String sLoc, String sScope, int inst) {
    MyEmailType ee = myFpaFac.createMyEmailType();
    ee.setEmailAddress("joe.schmoe-10" + inst + "@" + sLoc + sScope + ".me.com" );
    return ee;
  }

  /************
   * resources
   * @return
   * @throws Exception
   */
  private static InputStream[] readSchemas() throws Exception {
    InputStream[] afis = new InputStream[2];
    String sMain = S_SchemaPkg.replace('.', '/')  + "/" + S_SchemaBase;
    String sInfo = S_SchemaPkg.replace('.', '/')  + "/" + S_SchemaExtn;
    if (B_UseSchemas) {
      afis[0] = ClassLoader.getSystemResourceAsStream(sMain);
      afis[1] = ClassLoader.getSystemResourceAsStream(sInfo);
      if ((afis[0] == null) || (afis[1] == null)) {
        throw new IllegalArgumentException("Failed to locate schema source: " + sMain);
      }
    }
    return afis;
  }

  /************
   * main
   * @param asArg
   */
  public static void main(String[] asArg) {
    int res = 0;
    boolean doRead = true;
    boolean doWrit = true;
    try {
      // schemas
      InputStream[] afis = readSchemas();
      // FutureProofAdvert
      TestScd inst = new TestScd(MyItemHolder.class, afis);
      // in
      if (doRead) {
        inst.readTest();
      }
      // ot
      if (doWrit) {
        inst.writeTest();
      }
    }
    catch(Throwable th) {
      myLogger.log(Level.SEVERE, "Failed test", th);;
      res = 1;
    }
    finally {
      System.exit(res);
    }
  }
}
