/*
 * File    : PiecesItem.java
 * Created : 24 nov. 2003
 * By      : Olivier
 *
 * 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.ui.swt.views.tableitems.mytorrents;

import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;

import org.gudy.azureus2.core3.disk.DiskManager;
import org.gudy.azureus2.core3.disk.DiskManagerPiece;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.ui.swt.mainwindow.Colors;
import org.gudy.azureus2.ui.swt.mainwindow.SWTThread;
import org.gudy.azureus2.ui.swt.plugins.UISWTGraphic;
import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTGraphicImpl;
import org.gudy.azureus2.ui.swt.views.table.CoreTableColumnSWT;
import org.gudy.azureus2.ui.swt.views.table.TableCellSWT;

import org.gudy.azureus2.plugins.download.DownloadTypeIncomplete;
import org.gudy.azureus2.plugins.ui.Graphic;
import org.gudy.azureus2.plugins.ui.tables.*;

/**
 *
 * @author Olivier
 * @author TuxPaper (2004/Apr/17: modified to TableCellAdapter)
 */
public class PiecesItem
	extends CoreTableColumnSWT
	implements TableCellAddedListener, TableCellRefreshListener,
	TableCellDisposeListener
{
	public static final Class DATASOURCE_TYPE = DownloadTypeIncomplete.class;

	private final static int INDEX_COLOR_NONEAVAIL = Colors.BLUES_DARKEST + 1;

	// only supports 0 or 1 border size
	private final static int borderHorizontalSize = 1;

	private final static int borderVerticalSize = 1;

	private final static int borderSplit = 1;

	// height of little completion bar above piece bar.
	private final static int completionHeight = 2;

	public static final String COLUMN_ID = "pieces";

	private int marginHeight = -1;
	
	/** Default Constructor */
	public PiecesItem(String sTableID) {
		this(sTableID,-1);
	}
	
	public void fillTableColumnInfo(TableColumnInfo info) {
		info.addCategories(new String[] {
			CAT_CONTENT,
			CAT_PROGRESS
		});
		info.setProficiency(TableColumnInfo.PROFICIENCY_INTERMEDIATE);
	}

	/**
	 * 
	 * @param sTableID
	 * @param marginHeight -- Margin height above and below the pieces graphic; used in cases where the row is very tall
	 */
	public PiecesItem(String sTableID, int marginHeight) {
		super(DATASOURCE_TYPE, COLUMN_ID, ALIGN_LEAD, 100, sTableID);
		this.marginHeight = marginHeight;
		initializeAsGraphic(POSITION_INVISIBLE, 100);
		setMinWidth(100);
	}

	public void cellAdded(TableCell cell) {
		if (marginHeight != -1) {
			cell.setMarginHeight(marginHeight);
		}
		cell.setFillCell(true);
	}

	public void dispose(TableCell cell) {
		// Named infoObj so code can be copied easily to the other PiecesItem
		DownloadManager infoObj = (DownloadManager) cell.getDataSource();
		if (infoObj == null)
			return;

		Image img = (Image) infoObj.getUserData("PiecesImage");
		if (img != null && !img.isDisposed())
			img.dispose();

		infoObj.setUserData("PiecesImageBuffer", null);
		infoObj.setUserData("PiecesImage", null);
	}

	public void refresh(TableCell cell) {
		/* Notes:
		 * We store our image and imageBufer in DownloadManager using
		 * setData & getData.
		 */

		// Named infoObj so code can be copied easily to the other PiecesItem
		DownloadManager infoObj = (DownloadManager) cell.getDataSource();
		long lCompleted = (infoObj == null) ? 0 : infoObj.getStats().getCompleted();

		boolean bForce = infoObj != null && infoObj.getUserData("PiecesImage") == null;

		if (!cell.setSortValue(lCompleted) && cell.isValid() && !bForce) {
			return;
		}

		if (infoObj == null)
			return;

		//Compute bounds ...
		int newWidth = cell.getWidth();
		if (newWidth <= 0)
			return;
		int newHeight = cell.getHeight();

		int x0 = borderVerticalSize;
		int x1 = newWidth - 1 - borderVerticalSize;
		int y0 = completionHeight + borderHorizontalSize + borderSplit;
		int y1 = newHeight - 1 - borderHorizontalSize;
		int drawWidth = x1 - x0 + 1;
		if (drawWidth < 10 || y1 < 3)
			return;
		boolean bImageBufferValid = true;
		int[] imageBuffer = (int[]) infoObj.getUserData("PiecesImageBuffer");
		if (imageBuffer == null || imageBuffer.length != drawWidth) {
			imageBuffer = new int[drawWidth];
			bImageBufferValid = false;
		}

		Image image = (Image) infoObj.getUserData("PiecesImage");
		GC gcImage;
		boolean bImageChanged;
		Rectangle imageBounds;
		if (image == null || image.isDisposed()) {
			bImageChanged = true;
		} else {
			imageBounds = image.getBounds();
			bImageChanged = imageBounds.width != newWidth
					|| imageBounds.height != newHeight;
		}
		if (bImageChanged) {
			if (image != null && !image.isDisposed()) {
				image.dispose();
			}
			image = new Image(SWTThread.getInstance().getDisplay(), newWidth,
					newHeight);
			imageBounds = image.getBounds();
			bImageBufferValid = false;

			// draw border
			gcImage = new GC(image);
			gcImage.setForeground(Colors.grey);
			if (borderHorizontalSize > 0) {
				if (borderVerticalSize > 0) {
					gcImage.drawRectangle(0, 0, newWidth - 1, newHeight - 1);
				} else {
					gcImage.drawLine(0, 0, newWidth - 1, 0);
					gcImage.drawLine(0, newHeight - 1, newWidth - 1, newHeight - 1);
				}
			} else if (borderVerticalSize > 0) {
				gcImage.drawLine(0, 0, 0, newHeight - 1);
				gcImage.drawLine(newWidth - 1, 0, newWidth - 1, newHeight - 1);
			}

			if (borderSplit > 0) {
				gcImage.setForeground(Colors.white);
				gcImage.drawLine(x0, completionHeight + borderHorizontalSize, x1,
						completionHeight + borderHorizontalSize);
			}
		} else {
			gcImage = new GC(image);
		}

		DiskManager disk_manager = infoObj.getDiskManager();

		DiskManagerPiece[] pieces = disk_manager == null ? null
				: disk_manager.getPieces();

		int nbPieces = infoObj.getNbPieces();

		try {

			int nbComplete = 0;
			int a0;
			int a1 = 0;
			for (int i = 0; i < drawWidth; i++) {
				if (i == 0) {
					// always start out with one piece
					a0 = 0;
					a1 = nbPieces / drawWidth;
					if (a1 == 0)
						a1 = 1;
				} else {
					// the last iteration, a1 will be nbPieces
					a0 = a1;
					a1 = ((i + 1) * nbPieces) / (drawWidth);
				}

				int index;

				if (a1 <= a0) {
					index = imageBuffer[i - 1];
				} else {
					int nbAvailable = 0;
					for (int j = a0; j < a1; j++)
						if (pieces != null && pieces[j].isDone())
							nbAvailable++;
					nbComplete += nbAvailable;
					index = (nbAvailable * Colors.BLUES_DARKEST) / (a1 - a0);
					//System.out.println("i="+i+";nbAvailable="+nbAvailable+";nbComplete="+nbComplete+";nbPieces="+nbPieces+";a0="+a0+";a1="+a1);
				}

				if (!bImageBufferValid || imageBuffer[i] != index) {
					imageBuffer[i] = index;
					bImageChanged = true;
					gcImage.setForeground(index == INDEX_COLOR_NONEAVAIL ? Colors.red
							: Colors.blues[index]);
					gcImage.drawLine(i + x0, y0, i + x0, y1);
				}
			}

			// pieces can sometimes be 0 due to timing or bad torrent (well, there's a bug with a /0 error
			// so it can happen somehow :)

			int limit = nbPieces == 0 ? 0 : ((drawWidth * nbComplete) / nbPieces);

			if (limit < drawWidth) {
				gcImage.setBackground(Colors.blues[Colors.BLUES_LIGHTEST]);
				gcImage.fillRectangle(limit + x0, borderHorizontalSize, x1 - limit,
						completionHeight);
			}

			gcImage.setBackground(Colors.colorProgressBar);
			gcImage.fillRectangle(x0, borderHorizontalSize, limit, completionHeight);
		} catch (Exception e) {
			System.out.println("Error Drawing PiecesItem");
			Debug.printStackTrace(e);
		}
		gcImage.dispose();

		Image oldImage = null;
		Graphic graphic = cell.getGraphic();
		if (graphic instanceof UISWTGraphic) {
			oldImage = ((UISWTGraphic) graphic).getImage();
		}
		if (bImageChanged || image != oldImage || !cell.isValid()) {
			if (cell instanceof TableCellSWT) {
				((TableCellSWT) cell).setGraphic(image);
			} else {
				cell.setGraphic(new UISWTGraphicImpl(image));
			}
			if (bImageChanged) {
				cell.invalidate();
			}
			infoObj.setUserData("PiecesImage", image);
			infoObj.setUserData("PiecesImageBuffer", imageBuffer);
		}
	}
}
