/*
 * Created on May 1, 2013
 * Created by Paul Gardner
 * 
 * Copyright 2013 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.
 * 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.stats;

import java.util.*;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;


import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.util.DisplayFormatters;
import org.gudy.azureus2.ui.swt.Messages;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.components.Legend;
import org.gudy.azureus2.ui.swt.components.graphics.MultiPlotGraphic;
import org.gudy.azureus2.ui.swt.components.graphics.ValueFormater;
import org.gudy.azureus2.ui.swt.components.graphics.ValueSource;
import org.gudy.azureus2.ui.swt.mainwindow.Colors;
import org.gudy.azureus2.ui.swt.plugins.UISWTView;
import org.gudy.azureus2.ui.swt.plugins.UISWTViewEvent;
import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTViewCoreEventListener;
import org.gudy.azureus2.ui.swt.views.utils.TagUIUtils;

import com.aelitis.azureus.core.tag.*;
import com.aelitis.azureus.ui.swt.utils.ColorCache;


public class TagStatsView 
	extends TagTypeAdapter
	implements UISWTViewCoreEventListener, TagManagerListener
{	
	public static final String MSGID_PREFIX = "TagStatsView";
  
	private Composite 			panel;
	private Group	 			legend_panel;
	private ScrolledComposite	legend_panel_sc;
  
	private Composite			speed_panel;
	
	private UISWTView swtView;  
  
	private MultiPlotGraphic 		mpg;
	
	
	public 
	TagStatsView() 
	{
	}
  
 
	public void 
	periodicUpdate() 
	{

	}
  
	private void 
	initialize(
		Composite composite) 
	{
	    panel = new Composite(composite,SWT.NULL);	    
	    panel.setLayout(new GridLayout(2, false));
	    
	    legend_panel_sc = new ScrolledComposite(panel, SWT.V_SCROLL );
	    legend_panel_sc.setExpandHorizontal(true);
	    legend_panel_sc.setExpandVertical(true);
		GridLayout layout = new GridLayout();
		layout.horizontalSpacing = 0;
		layout.verticalSpacing = 0;
		layout.marginHeight = 0;
		layout.marginWidth = 0;
		legend_panel_sc.setLayout(layout);
		GridData gridData = new GridData(GridData.FILL_VERTICAL );
		legend_panel_sc.setLayoutData(gridData);
		
		legend_panel = new Group( legend_panel_sc, SWT.NULL );
		legend_panel.setText( MessageText.getString( "label.tags" ));
		
		legend_panel.setLayout(new GridLayout());

		legend_panel_sc.setContent(legend_panel);
		legend_panel_sc.addControlListener(new ControlAdapter() {
			public void controlResized(ControlEvent e) {
				legend_panel_sc.setMinSize(legend_panel.computeSize(SWT.DEFAULT, SWT.DEFAULT ));
			}
		});
	    
		speed_panel = new Composite( panel, SWT.NULL );
		speed_panel.setLayout(new GridLayout());
		gridData = new GridData(GridData.FILL_BOTH );
		speed_panel.setLayoutData(gridData);
		
	    build();
    
	    TagManager tm = TagManagerFactory.getTagManager();
	    
	    tm.addTagManagerListener( this, false );
	    
	    for ( TagType tt: tm.getTagTypes()){
	    	
	    	tt.addTagTypeListener( this, false );
	    }
	    
		panel.addListener( 
			SWT.Activate,
			new Listener()
			{
				public void 
				handleEvent(
					Event event )
				{
					refresh(true);
				}
			});
	}
  
	private void
	build()
	{
		if ( legend_panel == null || legend_panel.isDisposed()){
			
			return;
		}
		
		for ( Control c: legend_panel.getChildren()){
			
			c.dispose();
		}
		
		List<String>	configs 		= new ArrayList<String>();
		List<String>	texts			= new ArrayList<String>();	
		List<Color>		colors			= new ArrayList<Color>();
		
		TagManager tm = TagManagerFactory.getTagManager();
		
		List<TagType> tag_types = tm.getTagTypes();
		
		tag_types	= TagUIUtils.sortTagTypes( tag_types );
		
		List<TagFeatureRateLimit>	visible_tags = new ArrayList<TagFeatureRateLimit>();
				
		for ( TagType tag_type: tag_types ){
						
			if ( tag_type.hasTagTypeFeature( TagFeature.TF_RATE_LIMIT )){
				
				List<Tag> tags = tag_type.getTags();
				
				tags = TagUIUtils.sortTags( tags );
				
				for ( Tag tag: tags ){
					
					if ( !tag.isVisible()){
						
						continue;
					}
					
					TagFeatureRateLimit rl = (TagFeatureRateLimit)tag;

					if ( !rl.supportsTagRates()){
						
						continue;
					}
					
					String	config_key = "TagStatsView.cc." + tag_type.getTagType() + "." + tag.getTagID();
					
					configs.add( config_key );
					
					texts.add( tag.getTagName( true ));
					
					Color tt_colour;
					
					int[]	rgb = tag.getColor();
					
					if ( rgb == null ){
					
						tt_colour = Colors.blues[ Colors.BLUES_DARKEST];
             
					}else{
						
						tt_colour = ColorCache.getColor( legend_panel.getDisplay(), rgb );
					}
					
					colors.add( tt_colour );
					
					visible_tags.add( rl );
				}
			}
		}
		
		
		final Color[]		color_array = colors.toArray( new Color[ colors.size()]);
		final String[]		text_array = texts.toArray( new String[ texts.size()]);

	    final List<ValueSourceImpl>	sources = new ArrayList<ValueSourceImpl>();
	    	    
		List<int[]>	history_records 	= new ArrayList<int[]>();
		int			history_record_max	= 0;
		
	    for ( int i=0;i<visible_tags.size();i++ ){
	    	
	    	final TagFeatureRateLimit tag = visible_tags.get(i);

			tag.setRecentHistoryRetention( true );
			
			int[][] history = tag.getRecentHistory();
			
			history_record_max = Math.max( history[0].length, history_record_max );
			
			history_records.add( history[0] );
			history_records.add( history[1] );
	    	
	    	sources.add( new ValueSourceImpl( tag, text_array[i], i, color_array, true ));
	    	sources.add( new ValueSourceImpl( tag, text_array[i], i, color_array, false ));
	    };
		
	    ValueFormater formatter =
	    	new ValueFormater() 
	    	{
	        	public String 
	        	format(
	        		int value) 
	        	{
	        		return DisplayFormatters.formatByteCountToKiBEtcPerSec( value );
	        	}
	    	};
	      

		
		if ( mpg != null ){
			
			mpg.dispose();
		}

		final MultiPlotGraphic f_mpg = mpg = MultiPlotGraphic.getInstance( sources.toArray( new ValueSource[ sources.size()]), formatter );

		int[][] history = new int[history_records.size()][];
		
		for ( int i=0;i<history.length;i++){
			int[] 	hist 		= history_records.get(i);
			int		hist_len 	= hist.length;
			
			if ( hist_len == history_record_max ){
				history[i] = hist;
			}else{
				int[] temp = new int[history_record_max];
				System.arraycopy( hist, 0, temp, history_record_max-hist_len, hist_len );
				history[i] = temp;
			}
		}
		
		mpg.reset( history );
		
	    GridData gridData;
	    		
		if ( color_array.length > 0 ){
		
			gridData = new GridData( GridData.FILL_VERTICAL );
			gridData.verticalAlignment = SWT.CENTER;

			Legend.createLegendComposite(
				legend_panel, 
				color_array, 
				configs.toArray( new String[ configs.size()]), 
				text_array,
				gridData, 
				false,
				new Legend.LegendListener()
				{
					private int	hover_index = -1;
					
					public void 
					hoverChange(
						boolean 	entry, 
						int 		index ) 
					{
						if ( hover_index != -1 ){
							
							for ( int i=hover_index*2;i<hover_index*2+2;i++){
								
								sources.get(i).setHover( false );
							}
						}
						
						if ( entry ){
							
							hover_index = index;
							
							for ( int i=hover_index*2;i<hover_index*2+2;i++){
								
								sources.get(i).setHover( true );
							}
						}
											
						f_mpg.refresh( true );
					}
					
					public void
					visibilityChange(
						boolean	visible,
						int		index )
					{
						for ( int i=index*2;i<index*2+2;i++){
							
							sources.get(i).setVisible( visible );
						}
						
						f_mpg.refresh( true );
					}
				});
		}else{

			gridData = new GridData( GridData.FILL_HORIZONTAL );
			gridData.verticalAlignment = SWT.TOP;

			Label lab = new Label( legend_panel, SWT.NULL );
			lab.setText( MessageText.getString( "tag.stats.none.defined" ));
			
			lab.setLayoutData( gridData );
		}
		
		legend_panel_sc.setMinSize(legend_panel.computeSize(SWT.DEFAULT, SWT.DEFAULT ));
		
			// speed
		
		for ( Control c: speed_panel.getChildren()){
			
			c.dispose();
		}
				
	    Canvas speed_canvas = new Canvas( speed_panel,SWT.NO_BACKGROUND);
	    gridData = new GridData(GridData.FILL_BOTH);
	    speed_canvas.setLayoutData(gridData);


		mpg.initialize( speed_canvas, true );
		
	    panel.layout( true, true );
	    
	}
	
	private void
	rebuild()
	{
		Utils.execSWTThread(
			new Runnable()
			{
				public void
				run()
				{
					build();
				}
			});
	}
	
	private void
	rebuild(
		TagType		tag_type,
		boolean		added )
	{
		if ( panel == null || panel.isDisposed()){
			
			tag_type.getTagManager().removeTagManagerListener( this );
		
			return;
		}
		
		if ( added ){
			
			tag_type.addTagTypeListener( this, false );
		}
		
		rebuild();
	}
	
	public void
	tagTypeAdded(
		TagManager		manager,
		TagType			tag_type )
	{
		rebuild( tag_type, true );
	}
	
	public void
	tagTypeRemoved(
		TagManager		manager,
		TagType			tag_type )
	{		
		rebuild( tag_type, false );
	}
	
	private void
	rebuild(
		Tag			tag )
	{
		if ( panel == null || panel.isDisposed()){
			
			TagType tt = tag.getTagType();
			
			tt.removeTagTypeListener( this );
			
			tt.getTagManager().removeTagManagerListener( this );
			
			return;
		}
		
		rebuild();
	}
	
	public void
	tagAdded(
		Tag			tag )
	{
		rebuild( tag );
	}
	
	public void
	tagRemoved(
		Tag			tag )
	{
		rebuild( tag );
	}
	
	private void 
	delete() 
	{    
	    Utils.disposeComposite( panel );
	    
	    TagManager tm = TagManagerFactory.getTagManager();
	    
	    tm.removeTagManagerListener( this );
	    
	    for ( TagType tt: tm.getTagTypes()){
	    	
	    	tt.removeTagTypeListener( this );
	    }
	    
	    if ( mpg != null ){
	    	
	    	mpg.dispose();
	    }
	}


  
	private void 
	refresh(
		boolean force) 
	{
		if ( mpg != null ){
		
			mpg.refresh( force );
		}
	}  
  
	public boolean 
	eventOccurred(
		UISWTViewEvent event) 
	{
		switch (event.getType()) {
			case UISWTViewEvent.TYPE_CREATE:
				swtView = event.getView();
				swtView.setTitle(MessageText.getString(MSGID_PREFIX + ".title.full"));
				break;
	
			case UISWTViewEvent.TYPE_DESTROY:
				delete();
				break;
	
			case UISWTViewEvent.TYPE_INITIALIZE:
				initialize((Composite)event.getData());
				break;
	
			case UISWTViewEvent.TYPE_LANGUAGEUPDATE:
				Messages.updateLanguageForControl( panel );
				break;
	
			case UISWTViewEvent.TYPE_DATASOURCE_CHANGED:
				break;
	
			case UISWTViewEvent.TYPE_FOCUSGAINED:
				refresh(true);
				break;
	
			case UISWTViewEvent.TYPE_REFRESH:
				refresh(false);
				break;
	
			case StatsView.EVENT_PERIODIC_UPDATE:
				periodicUpdate();
				break;
		}

		return true;
	}
	
	private static class
	ValueSourceImpl
		implements ValueSource
	{	
		TagFeatureRateLimit		tag;
		String					name;
		int						index;
		Color[]					colours;
		boolean					is_up;
		
		private boolean			is_hover;
		private boolean			is_invisible;
		
		private
		ValueSourceImpl(
			TagFeatureRateLimit		_tag,
			String					_name,
			int						_index,
			Color[]					_colours,
			boolean					_is_up )
		{
			tag		= _tag;
			name	= _name;
			index	= _index;
			colours	= _colours;
			is_up	= _is_up;
		}
			
		public String
		getName()
		{
			return( name );
		}
		
		public Color 
		getLineColor() 
		{
			return( colours[index] );
		}
		
		public boolean
		isTrimmable()
		{
			return( false );
		}
		
		private void
		setHover(
			boolean	h )
		{
			is_hover = h;
		}
		
		public int 
		getAlpha() 
		{
			return( 255 );
		}
		
		private void
		setVisible(
			boolean	visible )
		{
			is_invisible = !visible;
		}
		
		public int 
		getStyle() 
		{
			if ( is_invisible ){
				
				return( STYLE_INVISIBLE );
			}
			
			int	style = is_up?STYLE_UP:STYLE_DOWN;
			
			if ( is_hover ){
				
				style |= STYLE_BOLD;
			}
			
			return( style );
		}
		
		public int
		getValue()
		{
			int rate = is_up?tag.getTagCurrentUploadRate():tag.getTagCurrentDownloadRate();
			
			if ( rate < 0 ){
				
				rate = 0;
			}
			
			return( rate );
		}
	}
}
