/*
 * Copyright (C) 2004, 2005, 2006 Aelitis SAS, 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.
 *
 * 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
 *
 * AELITIS, SAS au capital de 46,603.30 euros,
 * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
 */
 
package org.gudy.azureus2.ui.swt.views.tableitems.pieces;

import java.util.Arrays;

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

import org.gudy.azureus2.core3.disk.DiskManager;
import org.gudy.azureus2.core3.peer.PEPiece;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.ui.swt.mainwindow.Colors;
import org.gudy.azureus2.ui.swt.mainwindow.SWTThread;
import org.gudy.azureus2.ui.swt.views.table.TableCellSWT;
import org.gudy.azureus2.ui.swt.views.table.utils.CoreTableColumn;

import com.aelitis.azureus.core.diskmanager.cache.CacheFileManagerFactory;
import com.aelitis.azureus.core.diskmanager.cache.CacheFileManagerStats;

import org.gudy.azureus2.plugins.ui.tables.*;

/**
 *
 * @author TuxPaper
 * @since 2.0.8.5
 */
public class BlocksItem
       extends CoreTableColumn 
       implements TableCellAddedListener
{
	private final int COLOR_REQUESTED = 0;
	private final int COLOR_WRITTEN = 1;
	private final int COLOR_DOWNLOADED = 2;
	private final int COLOR_INCACHE = 3;
	public static Color[] colors = new Color[] {
    Colors.blues[Colors.BLUES_MIDLIGHT],
    Colors.blues[Colors.BLUES_DARKEST],
    Colors.red,
    Colors.grey
	};
  
  /** Default Constructor */
  public BlocksItem() {
    super("blocks", TableManager.TABLE_TORRENT_PIECES);
    initializeAsGraphic(POSITION_LAST, 200);
  }

  public void cellAdded(TableCell cell) {
    new Cell(cell);
  }

  private class Cell
          implements TableCellRefreshListener, TableCellDisposeListener
  {
    
    CacheFileManagerStats cacheStats; 
    public Cell(TableCell cell) {
      cell.setFillCell(true);
			cell.addListeners(this);
      try {
        cacheStats = CacheFileManagerFactory.getSingleton().getStats();
      } catch(Exception e) {
        e.printStackTrace();
      }
    }

    public void dispose(TableCell cell) {
      Image img = ((TableCellSWT)cell).getGraphicSWT();
      if (img != null && !img.isDisposed())
        img.dispose();
      
      // listeners don't need to be removed on dispose (core removed them)
    }

    public void refresh(TableCell cell) {
      PEPiece pePiece = (PEPiece)cell.getDataSource();
      if (pePiece == null) {
        cell.setSortValue(0);
      	dispose(cell);
        cell.setGraphic(null);
        return;
      }

      cell.setSortValue(pePiece.getNbWritten());
      long lNumBlocks = pePiece.getNbBlocks();
      
      int newWidth = cell.getWidth();
      if (newWidth <= 0) {
      	dispose(cell);
        cell.setGraphic(null);
        return;
      }
      int newHeight = cell.getHeight();
  
      int x1 = newWidth - 2;
      int y1 = newHeight - 3;
      if (x1 < 10 || y1 < 3) {
      	dispose(cell);
        cell.setGraphic(null);
        return;
      }
      Image image = new Image(SWTThread.getInstance().getDisplay(), 
                              newWidth, newHeight);
      Color color;
      GC gcImage = new GC(image);
      gcImage.setForeground(Colors.grey);
      gcImage.drawRectangle(0, 0, x1 + 1, y1 + 1);
      int blocksPerPixel = 0;
      int iPixelsPerBlock = 0;
      int pxRes = 0;
      long pxBlockStep = 0;
      int factor = 4;
      
      
      while(iPixelsPerBlock <= 0) {
        blocksPerPixel++;
        iPixelsPerBlock = (int) ((x1 + 1) / (lNumBlocks / blocksPerPixel) );        
      }
      
      pxRes = (int) (x1 - ((lNumBlocks / blocksPerPixel) * iPixelsPerBlock)); // kolik mi zbyde
      if (pxRes<=0)
        pxRes=1;
      pxBlockStep =(lNumBlocks*factor) / pxRes;	// kolikaty blok na +1 k sirce
      long addBlocks =(lNumBlocks*factor) / pxBlockStep;
      if ( (addBlocks*iPixelsPerBlock) > pxRes)
        pxBlockStep+=1;
      
/*      String msg = "iPixelsPerBlock = "+iPixelsPerBlock + ", blocksPerPixel = " + blocksPerPixel;
      msg += ", pxRes = " + pxRes + ", pxBlockStep = " + pxBlockStep + ", addBlocks = " + addBlocks + ", x1 = " + x1;
      Debug.out(msg);*/
      
      TOTorrent torrent = pePiece.getManager().getDiskManager().getTorrent();
      
      boolean[]	written 	= pePiece.getDMPiece().getWritten();
      boolean	piece_written 	= pePiece.isWritten();
      int	drawnWidth	= 0;
      int	blockStep	= 0;

      
      int pieceNumber = pePiece.getPieceNumber();
      long[] offsets = new long[(int)lNumBlocks];
      long[] lengths = (long[])offsets.clone();
      Arrays.fill(offsets, (long)pePiece.getManager().getDiskManager().getPieceLength()*(long)pieceNumber);
      for (int i = 0; i<lNumBlocks;lengths[i]=pePiece.getBlockSize(i),offsets[i]+=DiskManager.BLOCK_SIZE * i,i++ );

      boolean[] isCached = cacheStats == null ? null : cacheStats.getBytesInCache(torrent,offsets,lengths); 


      
      
      for (int i = 0; i < lNumBlocks; i+=blocksPerPixel) {
        int nextWidth = iPixelsPerBlock;
	
		blockStep += blocksPerPixel*factor;
		if (blockStep >= pxBlockStep) { // pokud jsem prelezl dany pocet bloku, zvys tomuhle sirku
		    nextWidth += (int)(blockStep/pxBlockStep);
		    blockStep -= pxBlockStep;
		}
	
        if (i >= lNumBlocks - blocksPerPixel) {	// pokud je posledni, at zasahuje az na konec
	    nextWidth = x1 - drawnWidth;
        }
        color = Colors.white;
        
        if ( (written == null && piece_written) || (written != null && written[i]) ){
        	
          color = colors[COLOR_WRITTEN];
        	
        }else if (pePiece.isDownloaded(i)) {
        	
          color = colors[COLOR_DOWNLOADED];
          
        }else if (pePiece.isRequested(i)) {
        	
          color = colors[COLOR_REQUESTED];
        }
  
        gcImage.setBackground(color);
        gcImage.fillRectangle(drawnWidth + 1,1,nextWidth,y1);

        if(isCached[i]) {
          gcImage.setBackground(colors[COLOR_INCACHE]);
          gcImage.fillRectangle(drawnWidth + 1,1,nextWidth,3);
          

        }
    
        drawnWidth += nextWidth;
        
      }
      gcImage.dispose();

      Image oldImage = ((TableCellSWT)cell).getGraphicSWT();

      ((TableCellSWT)cell).setGraphic(image);
      if (oldImage != null && !oldImage.isDisposed())
        oldImage.dispose();
      
      gcImage.dispose();
    }
  }
}
