// Spatial Index Library
//
// Copyright (C) 2002  Navel Ltd.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Contact information:
//  Mailing address:
//    Marios Hadjieleftheriou
//    University of California, Riverside
//    Department of Computer Science
//    Surge Building, Room 310
//    Riverside, CA 92521
//
//  Email:
//    marioh@cs.ucr.edu
package org.geotools.caching.spatialindex.storagemanager;

import java.util.*;


public abstract class Buffer implements IBuffer {
    int m_capacity = 10;
    boolean m_bWriteThrough = false;
    IStorageManager m_storageManager = null;
    HashMap m_buffer = new HashMap();
    long m_hits = 0;

    public Buffer(IStorageManager sm, int capacity, boolean bWriteThrough) {
        m_storageManager = sm;
        m_capacity = capacity;
        m_bWriteThrough = bWriteThrough;
    }

    abstract void addEntry(int id, Entry entry);

    abstract void removeEntry();

    public byte[] loadByteArray(final int id) {
        byte[] ret = null;
        Entry e = (Entry) m_buffer.get(new Integer(id));

        if (e != null) {
            m_hits++;

            ret = new byte[e.m_data.length];
            System.arraycopy(e.m_data, 0, ret, 0, e.m_data.length);
        } else {
            ret = m_storageManager.loadByteArray(id);
            e = new Entry(ret);
            addEntry(id, e);
        }

        return ret;
    }

    public int storeByteArray(final int id, final byte[] data) {
        int ret = id;

        if (id == NewPage) {
            ret = m_storageManager.storeByteArray(id, data);

            Entry e = new Entry(data);
            addEntry(ret, e);
        } else {
            if (m_bWriteThrough) {
                m_storageManager.storeByteArray(id, data);
            }

            Entry e = (Entry) m_buffer.get(new Integer(id));

            if (e != null) {
                e.m_data = new byte[data.length];
                System.arraycopy(data, 0, e.m_data, 0, data.length);

                if (m_bWriteThrough == false) {
                    e.m_bDirty = true;
                    m_hits++;
                } else {
                    e.m_bDirty = false;
                }
            } else {
                e = new Entry(data);

                if (m_bWriteThrough == false) {
                    e.m_bDirty = true;
                }

                addEntry(id, e);
            }
        }

        return ret;
    }

    public void deleteByteArray(final int id) {
        Integer ID = new Integer(id);
        Entry e = (Entry) m_buffer.get(ID);

        if (e != null) {
            m_buffer.remove(ID);
        }

        m_storageManager.deleteByteArray(id);
    }

    public void flush() {
        Iterator it = m_buffer.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry me = (Map.Entry) it.next();
            Entry e = (Entry) me.getValue();
            int id = ((Integer) me.getKey()).intValue();

            if (e.m_bDirty) {
                m_storageManager.storeByteArray(id, e.m_data);
            }
        }

        m_storageManager.flush();
    }

    public void clear() {
        Iterator it = m_buffer.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry me = (Map.Entry) it.next();
            Entry e = (Entry) me.getValue();

            if (e.m_bDirty) {
                int id = ((Integer) me.getKey()).intValue();
                m_storageManager.storeByteArray(id, e.m_data);
            }
        }

        m_buffer.clear();
        m_hits = 0;
    }

    public long getHits() {
        return m_hits;
    }

    class Entry {
        byte[] m_data = null;
        boolean m_bDirty = false;

        Entry(final byte[] d) {
            m_data = new byte[d.length];
            System.arraycopy(d, 0, m_data, 0, d.length);
        }
    }
} // Buffer
