/*
* Copyright 2014 - LAit SpA
*				 Realizzato da Icona Management srl su commessa LAit SpA
* Copyright 2015- LAit SpA
*                                                  Aggiornato da LAit SpA
*
* Concesso in licenza a norma dell'EUPL, versione 1.1 o
* successive dell'EUPL (la "Licenza") non appena saranno
* approvate dalla Commissione europea;
* Non è possibile utilizzare l'opera salvo nel rispetto della Licenza.
* E' possibile ottenere una copia della Licenza al seguente indirizzo:
*
* http://ec.europa.eu/idabc/eupl
*
* Salvo diversamente indicato dalla legge applicabile o
* concordato per iscritto, il software distribuito secondo
* i termini della Licenza è distribuito "TAL QUALE",
* SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO,
* esplicite o implicite.
* Si veda la Licenza per la lingua specifica che disciplina
* le autorizzazioni e le limitazioni secondo i termini della
* Licenza.
*/
/**
 * 
 */
package it.laitspa.cpf.spring.sogei;

import it.gov.fatturapa.sdi.fatturapa.v1.FatturaElettronicaType;
import it.laitspa.cpf.faces.utils.versionefattura.VersioneFatturaPaHelper;
import it.laitspa.cpf.util.log.LogUtils;
import it.laitspa.cpf.util.security.SignatureVerifier;
import it.laitspa.xsd.resolver.XmlMarshaller;
import org.apache.commons.io.FilenameUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author andrea
 * 
 */
public class SogeiArchiveParser
{

  private String        extension;
  private byte[]        data;
  private StringBuilder sb;

  public SogeiArchiveParser(String extension, byte[] data)
  {
    this.extension = extension;
    this.data = data;
    this.sb = new StringBuilder();
  }

  public StringBuilder getSb()
  {
    return sb;
  }

  public void setSb(StringBuilder sb)
  {
    this.sb = sb;
  }

  public List<FatturaElettronicaType> parse()
  {
    List<FatturaElettronicaType> fatture = new ArrayList<FatturaElettronicaType>();

    if(extension.contains("xml"))
    {
      LogUtils.info(getClass(), "Parsing SDI xml file.");
      FatturaElettronicaType fattura = parseInvoice(data);
      fatture.add(fattura);
    }
    else if(extension.contains("p7m"))
    {
      LogUtils.info(getClass(), "Parsing SDI p7m file.");
      byte[] content = retrieveUnsignedContent(data);
      if(content == null)
      {
        LogUtils.error(getClass(),
            "Exception caught while extracting XML content from SDI file, uncrypted data is null.");
        return null;
      }
      FatturaElettronicaType fattura = parseInvoice(content);
      fatture.add(fattura);
    }
    else if(extension.contains("zip"))
    {
      LogUtils.info(getClass(), "Parsing SDI Zip archive.");
      ByteArrayInputStream bis = new ByteArrayInputStream(data);
      ZipInputStream zin = new ZipInputStream(new BufferedInputStream(bis));
      try
      {
        ZipEntry entry;
        while((entry = zin.getNextEntry()) != null)
        {
          LogUtils.info(getClass(), "Parsing entry " + entry.getName());

          ByteArrayOutputStream bos = new ByteArrayOutputStream();
          byte[] buffer = new byte[512];
          int count = 0;
          while((count = zin.read(buffer, 0, buffer.length)) != -1)
          {
            bos.write(buffer, 0, count);
          }
          bos.flush();
          bos.close();

          // Set unzipped byte
          //
          byte[] unzipped = bos.toByteArray();
          String zip_ext = FilenameUtils.getExtension(entry.getName());
          if(zip_ext == null || zip_ext.trim().length() < 1 || zip_ext.toUpperCase().equals("XML"))
          {
            FatturaElettronicaType fattura = parseInvoice(unzipped);
            fatture.add(fattura);
          }
          else if(zip_ext.contains("p7m"))
          {
            byte[] content = retrieveUnsignedContent(unzipped);
            if(content == null)
            {
              LogUtils
                  .error(getClass(),
                      "Exception caught while extracting XML content from p7m in Zip SDI file, uncrypted data is null.");
              return null;
            }
            FatturaElettronicaType fattura = parseInvoice(content);
            fatture.add(fattura);
          }
        }

        zin.close();

      }
      catch(Exception e)
      {
        LogUtils.error(getClass(), "Exception caugth while iterating on zip entries.", e);
        return null;
      }
    }

    return fatture;
  }

  private byte[] retrieveUnsignedContent(byte[] signed)
  {
    byte[] content = null;
    SignatureVerifier v = new SignatureVerifier(signed);
    content = v.getContentByEncrypted();
    return content;
  }

  private FatturaElettronicaType parseInvoice(byte[] data_i)
  {
    XmlMarshaller<FatturaElettronicaType> mr = new XmlMarshaller<FatturaElettronicaType>();
    ByteArrayInputStream bis = new ByteArrayInputStream(data_i);
    FatturaElettronicaType fattura = null;
    try
    {
      InputStream xsd = VersioneFatturaPaHelper.getFileXSD(data_i);
      mr.setBuffer(sb);
      fattura = mr.unmarshal(FatturaElettronicaType.class, bis, xsd);
    }
    catch(Exception e)
    {
      LogUtils.error(getClass(),
          "Cannot create FatturaElettronicaType from buffer inside archive.", e);
    }
    finally
    {
      try
      {
        bis.close();
      }
      catch(IOException e)
      {
        LogUtils.error(getClass(), e);
      }
    }

    return fattura;
  }

}
