package org.marc4j.samples;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.List;

//import org.marc4j.ErrorHandler;
import org.marc4j.MarcError;
import org.marc4j.MarcException;
import org.marc4j.MarcPermissiveStreamReader;
import org.marc4j.MarcReader;
import org.marc4j.MarcStreamWriter;
import org.marc4j.MarcWriter;
import org.marc4j.marc.Record;

public class PermissiveReaderExample
{

    /**
     * This test program demonstrates the use of the MarcPermissiveStreamReader 
     * to read Marc records, with the permissive setting turned on.  It also 
     * demonstrates the capability of printing out the error messages that are
     * generated when the MarcPermissiveStreamReader encounters records with 
     * structural error or encoding errors.
     * 
     *  When run in verbose mode, (by passing -v as the first parameter) the 
     *  program will display the entire record highlighting the lines in the 
     *  record that have errors that the permissive reader was able to detect 
     *  and make an attempt at correcting.  Following that the program will 
     *  list all of the errors that it found in the record.
     *  
     *  When run in verbose mode as described above, the program is useful for
     *  validating records.
     *  
     *  Shown below is the output generated when the program is run on the file
     *  error.mrc found in the resources sub-directory in the samples directory:
     *  
     *  Fatal Exception: error parsing data field for tag: 250 with data:    a1st ed.
     *  Typo         : Record terminator character not found at end of record length --- [ n/a : n/a ]
     *  Typo         : Record terminator appears after stated record length, reading extra bytes --- [ n/a : n/a ]
     *  Minor Error  : Field length found in record different from length stated in the directory. --- [ n/a : n/a ]
     *     LEADER 00715cam a2200205 a 4500
     *     001 12883376
     *     005 20030616111422.0
     *     008 020805s2002    nyu    j      000 1 eng  
     *     020   $a0786808772
     *     020   $a0786816155 (pbk.)
     *     040   $aDLC$cDLC$dDLC
     *     100 1 $aChabon, Michael.
     *     245 10$aSummerland /$cMichael Chabon.
     *     250   $a1st ed.
     *     260   $aNew York :$bMiramax Books/Hyperion Books for Children,$cc2002.
     *     300   $a500 p. ;$c22 cm.
     *     520   $aEthan Feld, the worst baseball player in the history of the game, finds himself recruited by a 100-year-old scout to help a band of fairies triumph over an ancient enemy.
     *     650  1$aFantasy.
     *     650  1$aBaseball$vFiction.
     *     650  1$aMagic$vFiction.
     * @param args - args
     */
    public static void main(String[] args)
    {
        PrintStream out = System.out;
        boolean verbose = Boolean.parseBoolean(System.getProperty("marc.verbose"));
        boolean veryverbose = Boolean.parseBoolean(System.getProperty("marc.verbose"));
        if (args[0].equals("-v")) 
        {
            verbose = true;
            String newArgs[] = new String[args.length-1];
            System.arraycopy(args, 1, newArgs, 0, args.length-1);
            args = newArgs;
        }
        if (args[0].equals("-vv")) 
        {
            verbose = true;
            veryverbose = true;
            String newArgs[] = new String[args.length-1];
            System.arraycopy(args, 1, newArgs, 0, args.length-1);
            args = newArgs;
        }
        String fileStr = args[0];
        File file = new File(fileStr);
        MarcReader readerNormal = null;
        MarcReader readerPermissive = null;
        boolean to_utf_8 = true;
       
        InputStream inNorm;
        InputStream inPerm;
        OutputStream patchedRecStream = null;
        MarcWriter patchedRecs = null;
   //     ErrorHandler errorHandler = new ErrorHandler();
        try
        {
            inNorm = new FileInputStream(file);
            readerNormal = new MarcPermissiveStreamReader(inNorm, false, to_utf_8);
            inPerm = new FileInputStream(file);
            readerPermissive = new MarcPermissiveStreamReader(inPerm, true, to_utf_8, "BESTGUESS");
        }
        catch (FileNotFoundException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (args.length > 1)
        {
            try
            {
                patchedRecStream = new FileOutputStream(new File(args[1]));
                patchedRecs = new MarcStreamWriter(patchedRecStream);
            }
            catch (FileNotFoundException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        while (readerNormal.hasNext() && readerPermissive.hasNext())
        {
            Record recNorm;
            Record recPerm;
            recPerm = readerPermissive.next();
            String strPerm = recPerm.toString();
            try {
                recNorm = readerNormal.next();
            }
            catch (MarcException me)
            {
                if (verbose)
                {
                    out.println("Fatal Exception: "+ me.getMessage());
                    dumpErrors(out, recPerm.getErrors());
                    showDiffs(out, null, strPerm);
                    out.println("-------------------------------------------------------------------------------------");
                }
                continue;
            }
            String strNorm = recNorm.toString();
            if (!strNorm.equals(strPerm))
            {
                if (verbose)
                {
                    dumpErrors(out, recPerm.getErrors());
                    showDiffs(out, strNorm, strPerm);
                    out.println("-------------------------------------------------------------------------------------");
                    
                }
                if (patchedRecs != null)
                {
                    patchedRecs.write(recPerm);
                }
            }
            else if (recPerm.hasErrors())
            {
                if (verbose)
                {
                    out.println("Results identical, but errors reported");
                    dumpErrors(out, recPerm.getErrors());
                    showDiffs(out, strNorm, strPerm);
                    out.println("-------------------------------------------------------------------------------------");
                }
                if (patchedRecs != null)
                {
                    patchedRecs.write(recPerm);
                }
            }
            else if (veryverbose)
            {
                showDiffs(out, strNorm, strPerm);                
            }
                
        }
    }

    public static void showDiffs(PrintStream out, String strNorm, String strPerm)
    {
        if (strNorm != null)
        {
            String normLines[] = strNorm.split("\n");
            String permLines[] = strPerm.split("\n");
            if (normLines.length == permLines.length)
            {
                for (int i = 0; i < normLines.length; i++)
                {
                    if (normLines[i].equals(permLines[i]))
                    {
                        out.println("   " + normLines[i]);
                    }
                    else
                    {
                        out.println(" < " + normLines[i]);
                        out.println(" > " + permLines[i]);                    
                    }
                }
            }
        }
        else
        {
            String permLines[] = strPerm.split("\n");
            for (int i = 0; i < permLines.length; i++)
            {
                out.println("   " + permLines[i]);
            }
        }

    }
    
	public static void dumpErrors(PrintStream out, List<MarcError> errors)
    {
        if (errors != null) 
        {
            Iterator<MarcError> iter = errors.iterator();
            while (iter.hasNext())
            {
                Object error = iter.next();
                out.println(error.toString());
            }
        }
    }
}
