// Copyright 2000-2005 FreeHEP
package org.freehep.graphicsio.pdf;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Hashtable;
import java.util.Vector;

/**
 * Implements the lookup tables.
 * <p>
 * 
 * @author Mark Donszelmann
 * @version $Id: freehep-graphicsio-pdf/src/main/java/org/freehep/graphicsio/pdf/PDF.java f493ff6e61b2 2005/12/01 18:46:43 duns $
 */
public class PDF {

    private int generationNumber = 0;

    private Hashtable<String, PDFRef> refsByName = new Hashtable<String, PDFRef>(); // of PDFRefs stored by name

    private Vector<PDFRef> refsByNumber = new Vector<PDFRef>(); // of PDFRefs stored by number

    private Vector<Integer> xrefsByNumber = new Vector<Integer>(); // of offsets stored by
                                                    // refnumber

    private int startXref = 0;

    protected PDFByteWriter out;

    PDF(PDFByteWriter out) {
        this.out = out;
        // add dummy element to refsByNumber and xrefsByNumber
        refsByNumber.addElement(new PDFRef("Dummy", 0, 0));
        xrefsByNumber.addElement(new Integer(999999));
    }

    public PDFName name(String name) {
        return new PDFName(name);
    }

    public PDFRef ref(String name) {
        if (name == null)
            return null;
        PDFRef ref = refsByName.get(name);
        if (ref == null) {
            int refNumber = refsByNumber.size();
            ref = new PDFRef(name, refNumber, generationNumber);
            refsByName.put(name, ref);
            refsByNumber.add(ref);
            xrefsByNumber.add(null);
        }
        return ref;
    }

    public PDFRef[] ref(String[] names) {
        PDFRef[] refs = new PDFRef[names.length];
        for (int i = 0; i < names.length; i++) {
            refs[i] = ref(names[i]);
        }
        return refs;
    }

    protected void setXRef(int objectNumber, int offset) {
        xrefsByNumber.set(objectNumber, new Integer(offset));
    }

    protected void xref() throws IOException {
        DecimalFormat offsetFormat = new DecimalFormat("0000000000");
        DecimalFormat linkFormat = new DecimalFormat("00000");
        startXref = out.getCount();
        out.printPlain("xref");
        out.println();
        out.printPlain(0 + " " + xrefsByNumber.size());
        out.println();

        // the free list header
        out.printPlain(offsetFormat.format(0) + " " + linkFormat.format(65535)
                + " f\r\n");

        // the used list
        for (int i = 1; i < xrefsByNumber.size(); i++) {
            Integer offsetObject = xrefsByNumber.get(i);
            if (offsetObject != null) {
                int offset = offsetObject.intValue();
                out.printPlain(offsetFormat.format(offset) + " "
                        + linkFormat.format(0) + " n\r\n");
            } else {
                PDFRef ref = refsByNumber.get(i);
                System.err.println("PDFWriter: PDFRef '" + ref.getName()
                        + "' is used but not defined.");
            }
        }

        out.println();
    }

    protected void trailer(String rootName, String docInfoName)
            throws IOException {
        out.println("trailer");
        PDFDictionary dictionary = new PDFDictionary(this, out);
        dictionary.entry("Size", refsByName.size());
        dictionary.entry("Root", ref(rootName));
        if (docInfoName != null)
            dictionary.entry("Info", ref(docInfoName));
        dictionary.close();

        out.println();
    }

    protected void startxref() throws IOException {
        out.println("startxref");
        out.println(startXref);

        out.println();
    }
}