/*
 * Copyright (C) Azureus Software, Inc, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details ( see the LICENSE file ).
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.gudy.azureus2.plugins.ui.tables;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.AEThread2;
import org.gudy.azureus2.plugins.ui.UIInstance;

import com.aelitis.azureus.ui.UIFunctions;
import com.aelitis.azureus.ui.UIFunctionsManager;
import com.aelitis.azureus.ui.common.table.impl.TableColumnImpl;


/**
 * 
 * Provides a simple way to get a TableCell refreshed more often than the normal GUI refresh cycle
 * It always clocks at 100ms
 * as well as time synchronization methods for cells showing animated icons
 * @author olivier
 *
 */
public class TableCellRefresher {
	
	private static TableCellRefresher instance = null;
	
	private  AEThread2 refresher;
	
	private Map<TableCell, TableColumn> mapCellsToColumn = new HashMap<TableCell, TableColumn>();
	
	private  long iterationNumber;
	
	private volatile boolean inProgress = false;

	private AERunnable runnable;
	
	private TableCellRefresher() {
		runnable = new AERunnable() {
			public void runSupport() {
				try {
					Map<TableCell, TableColumn> cellsCopy;
  				synchronized (mapCellsToColumn) {
  					cellsCopy = new HashMap<TableCell, TableColumn>(mapCellsToColumn);
  					mapCellsToColumn.clear();
  				}

  				for (TableCell cell : cellsCopy.keySet()) {
  					TableColumn column = (TableColumn) cellsCopy.get(cell);

  					try {
  						//cc.cell.invalidate();
  						if (column instanceof TableCellRefreshListener) {
  							((TableCellRefreshListener) column).refresh(cell);
  						}else if ( column instanceof TableColumnImpl ){
  							List<TableCellRefreshListener> listeners =((TableColumnImpl)column).getCellRefreshListeners();
  							for ( TableCellRefreshListener listener: listeners ){
  								listener.refresh(cell);
  							}
  						}
  
  					} catch (Throwable t) {
  						t.printStackTrace();
  					}
  				}
				} finally {
					inProgress = false;
				}
			}
		};
		
		refresher = new AEThread2("Cell Refresher",true) {
			public void run() {
				try {
					
					iterationNumber = 0;
					
					UIFunctions uif = UIFunctionsManager.getUIFunctions();
					
					while (true) {

						if ( uif != null ){
							
							int size;
							
							synchronized (mapCellsToColumn){
								
								size = mapCellsToColumn.size();
							}
							
							if ( size > 0 && !inProgress ){
								
								inProgress = true;
	  						
									// this whole class shouldn't be here, but as it is and
									// it is used by plugins then keep it around
								
								uif.runOnUIThread( UIInstance.UIT_SWT, runnable );
							}
						}
						
						Thread.sleep(100);

						iterationNumber++;
					}
				}catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		
		refresher.start();
	}
	
	
	private void _addColumnCell(TableColumn column,TableCell cell) {
		synchronized (mapCellsToColumn) {
			if (mapCellsToColumn.containsKey(cell)) {
				return;
			}
			mapCellsToColumn.put(cell, column);
		}
	}
	
	private int _getRefreshIndex(int refreshEvery100ms, int nbIndices) {
		if(refreshEvery100ms <= 0) return 1;
		if(nbIndices <= 0) return 1;
		
		return (int) ( (iterationNumber / refreshEvery100ms) % nbIndices);
	}
	
	private static synchronized TableCellRefresher getInstance() {
		if(instance == null) {
			instance = new TableCellRefresher();
		}
		return instance;
	}
	
	//Add a cell to be refreshed within the next iteration
	//The cell will only get refreshed once
	public static void addCell(TableColumn column,TableCell cell) {
		
		getInstance()._addColumnCell(column,cell);
	}
	
	
	
	public static int getRefreshIndex(int refreshEvery100ms, int nbIndices) {
		return getInstance()._getRefreshIndex(refreshEvery100ms, nbIndices);
	}

}
