package org.vishia.byteData.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.vishia.byteData.test.Mystruct_h;



/**This class demonstrates how to use ByteDataAccess with a derived class, 
 * which is generated via ZBNF and XSLT using a header file.
 * The generated class is MyStruct_h.
 * 
 * @author Hartmut Schorrig
 *
 */
public class TestByteDataFromHeader
{

  /**Array to store the raw data from an input file. 
   * The raw data are accessed using {@link org.vishia.byteData.test.MyStruct_h.MyStruct}
   */
  private byte[] dataInput;
  
  /**Array to store the raw data for an output file. 
   * The raw data are accessed using {@link org.vishia.byteData.test.MyStruct_h.MyStruct}
   */
  private byte[] dataOutput;
  
  
  /**A data class which helds the values from the binary file in a Java form.
   * There may be another order, not all values or additional values here.
   */
  private static class Data
  { int a,b,c;
    short[] x,y;
    float f;
    int m,n;
  }
  

  /**Instance to hold data. */
  final Data data = new Data();
  
  /**Calling from cmd line
   * @param args not used
   */
  public static void main(String [] args)
  {
    TestByteDataFromHeader main = new TestByteDataFromHeader();
    main.execute();
  }
  
  /**The main execute routine.
   * <ul>
   * <li>Generates example data and writes to "exampleData.bin", big endian.
   * <li>Reads this data from file.
   * <li>Writes the same data in little endian in file "exampleDataLEndian.bin".
   * </ul>
   */
  private void execute()
  {
    dataOutput = generateExampleData();
    writeOutput("exampleData.bin", dataOutput);
    
    dataInput = readInput("exampleData.bin");
    
    readStructure(dataInput);
    dataOutput = writeStructure();
    
    writeOutput("exampleDataLEndian.bin", dataOutput);
  }

  
  
  /**
   * @return
   */
  private static byte[] generateExampleData()
  {
    Mystruct_h.MyStruct dataAccess = new Mystruct_h.MyStruct();
    dataAccess.setBigEndian(true);  //because the data should be written in big endian.
    byte[] data = new byte[Mystruct_h.MyStruct.kIdxAfterLast];
    dataAccess.assignEmpty(data);
    dataAccess.set_a(0x1234abcd);
    dataAccess.set_b((short)0x2468);
    dataAccess.set_c((short)0xace0);
    //dataAccess.set_f(1.2345678F);
    
    for(int ii=0; ii < Mystruct_h.MyStruct.size_x; ii++) {
      dataAccess.set_x((short)(ii+1), ii);
    }
    for(int ii=0; ii < Mystruct_h.MyStruct.size_y; ii++) {
      dataAccess.set_y((short)(-2*ii), ii);
    }
      
    dataAccess.embeddedStruct.set_m(0x6776effe);
    dataAccess.embeddedStruct.set_n(0x3443abba);
    
    return data;
    
  }
  
  
  
  /**Reads from raw Data given in a byte[] array using the byteDataAccess,
   * sets the read values to {@link data}.
   * @param rawData raw data read from file.
   * @set data
   */
  private void readStructure(byte[] rawData)
  { Mystruct_h.MyStruct inputAccess = new Mystruct_h.MyStruct();
    inputAccess.setBigEndian(true);  //because the data are expected in big endian.
    try
    {
      inputAccess.assignData(rawData, rawData.length);
      data.a = inputAccess.get_a();
      data.b = (short)inputAccess.get_b();
      data.c = (short)inputAccess.get_b();
      data.x = new short[Mystruct_h.MyStruct.size_x];
      for(int ii = 0; ii < data.x.length; ii++){
        data.x[ii] = (short)inputAccess.get_x(ii);
      }
      data.y = new short[Mystruct_h.MyStruct.size_y];
      for(int ii = 0; ii < data.y.length; ii++){
        data.y[ii] = (short)inputAccess.get_y(ii);
      }
      data.m = inputAccess.embeddedStruct.get_m();  
      data.n = inputAccess.embeddedStruct.get_n();  
    } 
    catch (IllegalArgumentException exc)
    { //it shouldn't be thrown.
      exc.printStackTrace();
    }
  }
  
 
  /**Writes the {@link data} to raw Data in a byte[] array using the byteDataAccess,
   * @return rawData raw data read from file.
   * @use data
   */
  private byte[] writeStructure()
  { byte[] rawData = new byte[Mystruct_h.MyStruct.kIdxAfterLast];
  
    Mystruct_h.MyStruct outputAccess = new Mystruct_h.MyStruct();
    outputAccess.setBigEndian(false);
    try
    {
      outputAccess.assignEmpty(rawData);
      outputAccess.set_a(data.a);
      outputAccess.set_b((short)data.b);  //Note: explicit typecast is necessary
      outputAccess.set_c((short)data.c);  //and shows the really necessities.
      for(int ii = 0; ii < data.x.length; ii++){
        outputAccess.set_x(data.x[ii], ii);
      }
      for(int ii = 0; ii < data.y.length; ii++){
        outputAccess.set_y(data.y[ii], ii);
      }
      outputAccess.embeddedStruct.set_m(data.m);  
      outputAccess.embeddedStruct.set_n(data.n);  
    } 
    catch (Exception e)
    {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return rawData;
  }
  
 
  private static byte[] readInput(String sFile)
  {
    File fileRead = new File(sFile);
    byte[] data;
    try
    { int sizeInput = (int)fileRead.length();
      data = new byte[sizeInput];
      InputStream reader = new FileInputStream(fileRead);
      reader.read(data);
      
    } 
    catch (FileNotFoundException e)
    {
      data = null;
    } catch (IOException e)
    {
      data = null;
    }
    return data;
  }


  private static int writeOutput(String sFile, byte[] data)
  { int error;
    
    File fileWrite = new File(sFile);
    try
    { OutputStream writer = new FileOutputStream(fileWrite);
      writer.write(data);
      writer.close();
      error = 0;
    } 
    catch (FileNotFoundException e)
    {
      error = -1;
    } catch (IOException e)
    {
      error = -2;
    }
    return error;
  }


}
