/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2007 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.lib.jmbeans.monitoring;

import org.ow2.jonas.lib.timer.TimerEvent;
import org.ow2.jonas.lib.timer.TimerEventListener;
import org.ow2.jonas.lib.timer.TimerManager;

public class MemoryMonitoring implements TimerEventListener {
    /**
     * Memory monitoring objects
     */
    private int sizeTableMeasures = 120;
    private int range = 10;
    private Long[] tableMeasures;
    private long maxtotalmemory;
    private TimerEvent mytimer = null;
    private TimerManager timerManager = null;
    private boolean activated = false;

    public MemoryMonitoring() {
    }

    /**
     * Get the table of value.
     * @return Long[] measures table
     */
    public Long[] getTableMeasures() {
        return tableMeasures;
    }

	public boolean getActivated() {
		return activated;
	}

	public void setActivated(boolean pActivated) {
		if (pActivated) {
			if (!activated) {
				synchronized (this) {
					activated = true;
					initTable();
				}
				// launch timer
		    	long timeout = range * 1000;
		    	mytimer = timerManager.addTimerMs(this, timeout, new Integer(1), true);
			}
		} else {
			if (activated) {
				synchronized (this) {
					activated = false;
					initTable();
					// stop timer
					mytimer.stop();
					mytimer.unset();
				}
			}
		}
	}

    /**
     * Get range.
     * @return Integer - range
     */
    public int getRange() {
        return range;
    }
    /**
     * set range
     * @param range range for free memory measurement
     */
    public void setRange(int range) {
        if (this.range != range) {
            synchronized (this) {
                if (range < 10) {
                    throw new IllegalArgumentException("range could not be < 10");
                }
                this.range = range;
                // reset table values
                initTable();
                /// change range
                mytimer.change(this.range * 1000, new Integer(1));
            }
        }
    }

    /**
     * Get the size of the table of measures.
     * @return Number of measures
     */
    public int getSizeTableMeasures() {
        return sizeTableMeasures;
    }

    /**
     * Set the size of the table of measures
     * @param sizeMeasuresTable Number of measures
     */
    public void setSizeTableMeasures(int sizeMeasuresTable) {
        if (sizeMeasuresTable != this.sizeTableMeasures) {
            synchronized (this) {
                if (sizeMeasuresTable <= 1) {
                    throw new IllegalArgumentException("number of measures could not be <= 1");
                }
                this.sizeTableMeasures = sizeMeasuresTable;
                initTable();
            }
        }
    }

    /**
     * The measures timeout has expired.
     * Do not synchronize this method to avoid deadlocks!
     * @param arg Object
     */
    public void timeoutExpired(Object arg) {
    	// TODO Auto-generated method stub
    	int argvalue = ((Integer) arg).intValue();
    	switch (argvalue) {
    	case 1:

    		//timeout expired
    		long uvalue = usedMemory();
    		long tmvalue = totalMemory();

    		// put the max total memory
    		if (tmvalue > maxtotalmemory) {
    			maxtotalmemory = tmvalue;
    		}
    		for (int i = 0; i < tableMeasures.length; i++) {
    			if (i != tableMeasures.length - 1) {
    				tableMeasures[i] = tableMeasures[i + 1];
    			} else {
    				tableMeasures[i] = new Long(uvalue);
    			}
    		}
    		break;
    	default:

    		//timeoutExpired do nothing;
    		break;
    	}
	}

    /**
     * Initialize table of measures.
     */
    private void initTable() {
        tableMeasures = new Long[sizeTableMeasures];
        // init max totalmemory
        maxtotalmemory = totalMemory();
        for (int i = 0; i < tableMeasures.length; i++) {
            tableMeasures[i] = new Long(0);
        }
        // init the first value
        tableMeasures[tableMeasures.length - 1] = new Long(usedMemory());
    }

    /**
     * private function for monitoring
     * @return long  used memory
     */
    public long usedMemory() {
        long result = -1;
        while (result < 0) {
            result = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        }

        return result / 1000;
    }

    /**
     * Private function for monitoring.
     * @return long  total memory
     */
    public long totalMemory() {
        return Runtime.getRuntime().totalMemory() / 1000;
    }

	public TimerManager getTimerManager() {
		return timerManager;
	}

	public void setTimerManager(TimerManager timerManager) {
		this.timerManager = timerManager;
	}

}
