package jp.hasc.hasctool.ui.views;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableSet;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

import jp.hasc.hasctool.core.data.DefaultVectorSignalComparator;
import jp.hasc.hasctool.core.data.LabelInfo;
import jp.hasc.hasctool.core.data.LabelSignalMessage;
import jp.hasc.hasctool.core.data.NullSignalMessage;
import jp.hasc.hasctool.core.data.ObjectSignalMessage;
import jp.hasc.hasctool.core.data.SignalMessage;
import jp.hasc.hasctool.core.data.VectorSignalMessage;
import jp.hasc.hasctool.core.data.VectorSignalMessages;
import jp.hasc.hasctool.core.messaging.MessageProcessor;
import jp.hasc.hasctool.core.util.CoreUtil;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Slider;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

/**
 * SpectrogramViewのWidgetです
 * @author hiro,iwasaki
 */
public class SpectrogramViewWidget extends Composite {
	/**
	 * @author hiro,iwasaki
	 */
	private final class CopyLinkSelectionListener implements SelectionListener {
		@Override
		public void widgetSelected(SelectionEvent e) {
			String text=e.text;
			LOG.debug("toClipboard: "+text);
			CoreUtil.copyToClipboard(getShell().getDisplay(), text);          
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent e) {
		}
	}  

	/** logger for this class */
	private final static org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory
			.getLog(SpectrogramViewWidget.class);

	private static final int REFRESH_DELAY_MS = 1000 / 30;
	
	private Canvas canvas_;
	private Slider slider_;
	private long sliderUnitTime_;
	private Label topLabel_;
	private Link timeLabel_;
	private ToolBar toolBar_;
	private double frequency_;
	private boolean showScale_=true;
	
	public SpectrogramViewWidget(Composite parent, int style) {
		super(parent,style);
		this.setLayout(new FormLayout());
		
		toolBar_ = new ToolBar(this, SWT.VERTICAL);
		{
			FormData fd = new FormData();
			fd.top=new FormAttachment(0, 1);
			fd.right=new FormAttachment(100, -1);
			fd.bottom=new FormAttachment(100, -1);
			toolBar_.setLayoutData(fd);
		}
		{
			ToolItem ti=new ToolItem(toolBar_, SWT.NONE);
			ti.setText("+t");
			ti.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					long pos=getViewTimeMax();
					setViewTimeWidth(getViewTimeWidth()/2);
					doRequestedUpdateTimeRange();
					setViewTimeMax(pos);
					doRedraw();
				}
			});
		}
		{
			ToolItem ti=new ToolItem(toolBar_, SWT.NONE);
			ti.setText("-t");
			ti.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					long pos=getViewTimeMax();
					setViewTimeWidth(getViewTimeWidth()*2);
					doRequestedUpdateTimeRange();
					setViewTimeMax(pos);
					doRedraw();
				}
			});
		}
		{
			ToolItem ti=new ToolItem(toolBar_, SWT.NONE);
			ti.setText("+v");
			ti.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					setValueHeight(getValueHeight()/2);
					setValueMin(getValueMin()/2);
					requestRedraw();
				}
			});
		}
		{
			ToolItem ti=new ToolItem(toolBar_, SWT.NONE);
			ti.setText("-v");
			ti.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					setValueHeight(getValueHeight()*2);
					setValueMin(getValueMin()*2);
					requestRedraw();
				}
			});
		}
		{
			ToolItem ti=new ToolItem(toolBar_, SWT.NONE);
			ti.setText("rt");
			ti.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					if (viewTimeOffset_==0) {
						viewTimeOffset_=waveDataTimeMin_;
					}else{
						viewTimeOffset_=0;
					}
					requestRedraw();
				}
			});
		}
		
		//
		topLabel_ = new Label(this, SWT.WRAP);
		{
			FormData fd = new FormData();
			fd.top=new FormAttachment(0, 1);
			fd.left=new FormAttachment(0, 1);
			fd.right=new FormAttachment(70, -1);
			topLabel_.setLayoutData(fd);
		}
		
		timeLabel_ = new Link(this, SWT.WRAP);
		{
			FormData fd = new FormData();
			fd.top=new FormAttachment(0, 1);
			fd.left=new FormAttachment(topLabel_, 1);
			fd.right=new FormAttachment(toolBar_, -1);
			timeLabel_.setText("time:");
			timeLabel_.setLayoutData(fd);
			timeLabel_.addSelectionListener(new CopyLinkSelectionListener());
		}
		
		slider_ = new Slider(this, SWT.NONE);
		{
			FormData fd = new FormData();
			fd.left=new FormAttachment(0, 1);
			fd.bottom=new FormAttachment(100, -1);
			fd.right=new FormAttachment(toolBar_, -1);
			sliderUnitTime_ = SignalMessage.TIME_UNIT.convert(1, TimeUnit.MILLISECONDS);
			slider_.setLayoutData(fd);
			slider_.setMinimum(0);
			slider_.setIncrement(10);
			slider_.addSelectionListener(new SelectionListener() {
				
				@Override
				public void widgetSelected(SelectionEvent e) {
					synchronized(waveData_) {
						synchronized (labelData_) {
							int pos=slider_.getSelection()+slider_.getThumb();
							viewTimeMax_=pos*sliderUnitTime_+waveDataTimeMin_;
						}
					}
					//requestRedraw();
					doRedraw();
				}
				
				@Override
				public void widgetDefaultSelected(SelectionEvent e) {
				}
			});
		}
		
		canvas_ = new Canvas(this, SWT.BORDER | SWT.DOUBLE_BUFFERED);
		{
			FormData fd = new FormData();
			fd.top=new FormAttachment(topLabel_, 1);
			fd.left=new FormAttachment(0, 1);
			fd.bottom=new FormAttachment(slider_, -1);
			fd.right=new FormAttachment(toolBar_, -1);
			canvas_.setLayoutData(fd);
			canvas_.addPaintListener(new PaintListener() {
				@Override
				public void paintControl(PaintEvent e) {
					onCanvasPaint(e);
				}
			});
			
			// time picker
			canvas_.addMouseListener(new MouseListener() {
				int downX_,downY_; 
				
				@Override
				public void mouseUp(MouseEvent e) {
					if (e.button==1) {
						if (Math.abs(downX_-e.x)>2 || Math.abs(downY_-e.y)>2) {
							// range
							timeMarkerEnd_=getTimeAtCanvasX(e.x,getCanvasWidth());
							if (timeMarkerEnd_<timeMarkerBegin_) {
								// swap
								Long tmp=timeMarkerBegin_; timeMarkerBegin_=timeMarkerEnd_; timeMarkerEnd_=tmp;
							}
							timeLabel_.setText("time:<a>"+
									((viewTimeOffset_!=0)?"r ":"")+
									timeToSecond(timeMarkerBegin_-viewTimeOffset_)+","+timeToSecond(timeMarkerEnd_-viewTimeOffset_)+"</a>");
							requestRedraw();
						}
					}
				}
				
				@Override
				public void mouseDown(MouseEvent e) {
					if (e.button==1) {
						downX_=e.x;
						downY_=e.y;
						timeMarkerBegin_=getTimeAtCanvasX(downX_,getCanvasWidth());
						// point
						timeMarkerEnd_=null;
						timeLabel_.setText("time:<a>"+
								((viewTimeOffset_!=0)?"r ":"")+
								timeToSecond(timeMarkerBegin_-viewTimeOffset_)+"</a>");
						requestRedraw();
					}else{
						timeMarkerBegin_=timeMarkerEnd_=null;
						timeLabel_.setText("time:");
						requestRedraw();
					}
				}

				@Override
				public void mouseDoubleClick(MouseEvent e) {
				}
			});
		}
		
		//
		clearData(DATA_BITS_ALL);
	}
	
	public static double timeToSecond(Long time) {
		return SignalMessage.TIME_UNIT.toMillis(time)/1000.0;
	}
	
	private Long timeMarkerBegin_=null, timeMarkerEnd_=null;
	private int signalDataCapacity_ = -1; // -1なら無制限
	private NavigableSet<VectorSignalMessage> waveData_=new TreeSet<VectorSignalMessage>(new DefaultVectorSignalComparator());
	private NavigableSet<LabelSignalMessage> labelData_=new TreeSet<LabelSignalMessage>();
	private long viewTimeMax_=0;
	private long viewTimeWidth_=SignalMessage.TIME_UNIT.convert(1000, TimeUnit.MILLISECONDS);
	private long viewTimeOffset_=0;
	private long waveDataTimeMin_=0, waveDataTimeMax_=0;
	private double valueMin_=0;
	private double valueHeight_=-valueMin_*2;
	
	private Color[] labelColors_=new Color[]{new Color(null,255,255,128), new Color(null,200,255,255), new Color(null,255,200,255),
			new Color(null,255,200,128), new Color(null,200,200,255), new Color(null,200,255,128), new Color(null,200,200,200) };
	private Map<String,Color> labelColorMap_=new HashMap<String,Color>();
	
	private int getCanvasWidth() {
		return canvas_.getSize().x-canvas_.getBorderWidth()*2;
	}
	private int getCanvasHeight() {
		return canvas_.getSize().y-canvas_.getBorderWidth()*2;
	}
	
	private Color getVectorColor(double val) {
		float col =(float)((val-valueMin_)/valueHeight_);
		if(col>1.0f)col=1.0f;
		if(col<0.0f)col=0.0f;
		col = 0.75f*(1.0f-col);
		java.awt.Color cc = java.awt.Color.getHSBColor(col,1.0f,1.0f);
		return new Color(null,cc.getRed(),cc.getGreen(),cc.getBlue());
	}
	
	/** draw view */
	private void onCanvasPaint(PaintEvent e) {
		requestedRedraw_=false;
		//
		GC gc = e.gc;
		int cw=getCanvasWidth(), ch=getCanvasHeight();
		
		// bg
		gc.setBackground(new Color(null,255,255,255));
		gc.fillRectangle(0,0,cw,ch);
		
		// pick labels
		NavigableSet<LabelSignalMessage> labels=null;
		synchronized(labelData_) {
			if (!labelData_.isEmpty()){
				LabelSignalMessage first=labelData_.lower(LabelSignalMessage.createEmpty(viewTimeMax_-viewTimeWidth_));
				if (first==null) first=labelData_.first();
				LabelSignalMessage last=labelData_.ceiling(LabelSignalMessage.createEmpty(viewTimeMax_+1));
				if (last==null) last=labelData_.last();
				labels = labelData_.subSet(first,true,last,true);
			}
		}
		
		// label BG
		if (labels!=null){
			HashMap<LabelInfo,LabelSignalMessage> beginSigs=new HashMap<LabelInfo, LabelSignalMessage>();
			for(LabelSignalMessage lblSig:labels) {
				gc.setBackground(getLabelBgColor(lblSig.getLabelInfo()));
				switch(lblSig.getType()) {
				case BEGIN:
					beginSigs.put(lblSig.getLabelInfo(), lblSig);
					break;
				case END:
					LabelSignalMessage beginSig = beginSigs.get(lblSig.getLabelInfo());
					int x0=0;
					int x1=getWaveX(lblSig.getTime(), cw);
					if (beginSig!=null) {
						beginSigs.remove(lblSig.getLabelInfo());
						x0=getWaveX(beginSig.getTime(), cw);
					}
					gc.fillRectangle(x0, 0, x1-x0, ch);
					break;
				}
			}
			for(LabelSignalMessage beginSig : beginSigs.values()) {
				gc.setBackground(getLabelBgColor(beginSig.getLabelInfo()));
				int x0=getWaveX(beginSig.getTime(), cw);
				gc.fillRectangle(x0, 0, cw-x0, ch);
			}
			beginSigs.clear();
		}    
		
		// timeMarker BG
		gc.setBackground(new Color(null,200,200,200));
		if (timeMarkerBegin_!=null && timeMarkerEnd_!=null) {
			int x0=getWaveX(timeMarkerBegin_, cw);
			int x1=getWaveX(timeMarkerEnd_, cw);
			gc.fillRectangle(x0, 0, x1-x0, ch);
		}
		
		// wave
		do {
			synchronized(waveData_) {
				if (waveData_.isEmpty()) break;
				//
				VectorSignalMessage first=waveData_.lower(VectorSignalMessages.createEmpty(viewTimeMax_-viewTimeWidth_));
				if (first==null) first=waveData_.first();
				VectorSignalMessage last=waveData_.ceiling(VectorSignalMessages.createEmpty(viewTimeMax_+1));
				if (last==null) last=waveData_.last();
				//
				int maxVectorSize=1;
				for(int idx=0;idx<maxVectorSize;++idx) {
					@SuppressWarnings("unused")
					SignalMessage prevElem=null;
					int prevX=0;
					for(VectorSignalMessage elem: waveData_.subSet(first,true,last,true)) {
						int vsize = elem.getVectorSize();
						if (vsize<=idx) continue;
						if (maxVectorSize<vsize) maxVectorSize=vsize;
						//
						int x=getWaveX(elem.getTime(), cw);
						int y1=getWaveY(idx, maxVectorSize, ch);
						int y0=getWaveY(idx+1, maxVectorSize, ch);
						double val=elem.getVectorElement(idx);
						Color color = getVectorColor(val);
						gc.setForeground(color);
						gc.setBackground(color);
						gc.fillRectangle(prevX, y0, x-prevX,y1-y0);
						prevElem=elem;
						prevX=x;
					}
				}
			}
		}while(false);
		
		// scale
		if (isShowScale()) {
			FontMetrics fm = gc.getFontMetrics();
			gc.setForeground(new Color(null,0,0,0));
			double valueMax = valueMin_+valueHeight_;
			// v scale
			if (valueMax!=0)gc.drawText(""+valueMax,0,ch-fm.getHeight(), true);
			gc.drawText(Double.toString(frequency_)+"(Hz)" ,0,0, true);
		}
		
		// label edges
		if (labels!=null){
			gc.setForeground(new Color(null,0,0,0));
			for(LabelSignalMessage lblSig:labels) {
				gc.setBackground(getLabelBgColor(lblSig.getLabelInfo()));
				int x1=getWaveX(lblSig.getTime(), cw);
				int h=gc.getFontMetrics().getHeight()+4;
				gc.drawLine(x1, 0, x1, ch);
				String lblStr=lblSig.getLabelInfo().getLabel();
				switch(lblSig.getType()) {
				case BEGIN:
					gc.drawText(lblStr, x1+2, ch-h+2, false);
					break;
				case END:
					int w=gc.stringExtent(lblStr).x;
					gc.drawText(lblStr, x1-2-w, ch-h+2, false);
					break;
				}
			}
		}
		
		// timeMarker
		gc.setForeground(new Color(null,64,64,128));
		if (timeMarkerBegin_!=null) {
			int x=getWaveX(timeMarkerBegin_, cw);
			gc.drawLine(x, 0, x, ch);
		}
		if (timeMarkerEnd_!=null) {
			int x=getWaveX(timeMarkerEnd_, cw);
			gc.drawLine(x, 0, x, ch);
		}
	}

	private Color getLabelBgColor(LabelInfo labelInfo) {
		String lblstr = labelInfo.getLabel();
		Color c=labelColorMap_.get(lblstr);
		if (c!=null) return c;
		c=labelColors_[labelColorMap_.size()%labelColors_.length];
		labelColorMap_.put(lblstr, c);
		return c;
	}

	public static String getTimeString(long t) {
		return (TimeUnit.MILLISECONDS.convert(t, SignalMessage.TIME_UNIT)/1000.f)+"s";
	}
	
	private long getTimeAtCanvasX(int x, int canvasWidth) {
		int w=canvasWidth-3;
		return (x-1-w)*viewTimeWidth_/w + viewTimeMax_;
	}

	private int getWaveX(long time, int canvasWidth) {
		int w=canvasWidth-3;
		return 1+(int)(w+w*(time-viewTimeMax_)/viewTimeWidth_);
	}

	private int getWaveY(int idx, int num, int canvasHeight) {
		int h=canvasHeight-3;
		return 1+(int)(h-h*(idx)/(num+1));
	}

	private boolean requestedUpdateTimeRangeAndRedraw=false;
	
	/** should be called from SWT thread */
	private void doRequestedUpdateTimeRange() {
		synchronized(waveData_) {
			if (!waveData_.isEmpty()) {
				
				// trim waveData within capacity
				if (signalDataCapacity_>=0) {
					int trimmingNum=waveData_.size()-signalDataCapacity_;
					if (trimmingNum>0) {
						for(Iterator<VectorSignalMessage> it=waveData_.iterator(); it.hasNext() && trimmingNum>0; --trimmingNum) {
							it.next();
							it.remove();
						}
					}
				}
				
				// range
				waveDataTimeMin_=waveData_.first().getTime();
				waveDataTimeMax_=waveData_.last().getTime();
			}
		}
		synchronized (labelData_) {
			if (!labelData_.isEmpty()) {
				// todo: trim LabelData？
				
				// 表示範囲を、ラベルの範囲に拡張
				long labelTimeMin=labelData_.first().getTime();
				long labelTimeMax=labelData_.last().getTime();
				if (waveDataTimeMin_>labelTimeMin) waveDataTimeMin_=labelTimeMin;
				if (waveDataTimeMax_<labelTimeMax) waveDataTimeMax_=labelTimeMax;
			}
		}
		
		// auto scroll
		if (followSlider_) {
			viewTimeMax_=waveDataTimeMax_;
		}
		
		// update slider
		if (!slider_.isDisposed()) {
				slider_.setMaximum((int)((waveDataTimeMax_-waveDataTimeMin_)/sliderUnitTime_));
				slider_.setThumb((int)(viewTimeWidth_/sliderUnitTime_));
		}
		setViewTimeMax(viewTimeMax_);
	}
	
	public void preventUpdates(boolean b) {
		if (b) {
			requestedUpdateTimeRangeAndRedraw=true;
			requestedRedraw_=true;
		}else{
			requestedUpdateTimeRangeAndRedraw=false;
			doRequestedUpdateTimeRange();
			doRedraw();
		}
	}
	
	public void requestUpdateTimeRangeAndRedraw() {
		if (requestedUpdateTimeRangeAndRedraw) return;
		requestedUpdateTimeRangeAndRedraw=true;
		requestedRedraw_=true;
		asyncTimerExec(REFRESH_DELAY_MS, new Runnable() {
			@Override
			public void run() {
				requestedUpdateTimeRangeAndRedraw=false;
				doRequestedUpdateTimeRange();
				doRedraw();
			}
		});
	}
	
	/** should be called from SWT thread */
	private void doRedraw() {
		if (!canvas_.isDisposed()) canvas_.redraw();
	}
	
	private boolean requestedRedraw_=false;

	private boolean followSlider_ = true;
	
	public void requestRedraw() {
		if (requestedRedraw_) return;
		requestedRedraw_=true;
		asyncTimerExec(REFRESH_DELAY_MS, new Runnable() {
			@Override
			public void run() {
				doRedraw();
			}
		});
	}
	
	private void asyncTimerExec(final int milliseconds, final Runnable runnable) {
		getDisplay().asyncExec(new Runnable() {
			@Override
			public void run() {
				getDisplay().timerExec(milliseconds, runnable);
			}
		});
	}
	
	private MessageProcessor inputPort_=new MessageProcessor() {
		@Override
		public void processMessage(Object message) {
			if (message instanceof VectorSignalMessage) {
				VectorSignalMessage vecMsg=(VectorSignalMessage)message;
				processVectorSignalMessage(vecMsg);
			}else if (message instanceof LabelSignalMessage) {
				processLabelMessage((LabelSignalMessage)message);
			}else if (message instanceof ObjectSignalMessage) {
				ObjectSignalMessage osm=(ObjectSignalMessage)message;
				SignalMessage[] sigs = (SignalMessage[]) osm.getValue();
				if (sigs.length==2 && sigs[0] instanceof VectorSignalMessage && sigs[1] instanceof ObjectSignalMessage) {
					// (VectorSignalMessage, LabelSignalMessage[]) の複合メッセージ
					VectorSignalMessage vecMsg=(VectorSignalMessage)sigs[0];
					processVectorSignalMessage(vecMsg);
					//
					ObjectSignalMessage labelMsgs=(ObjectSignalMessage) sigs[1];
					SignalMessage[] lbls=(SignalMessage[]) labelMsgs.getValue();
					for(SignalMessage lbl:lbls) {
						if (lbl instanceof LabelSignalMessage) {
							processLabelMessage((LabelSignalMessage)lbl);
						}else if (lbl instanceof NullSignalMessage) {
							// NOP
						}else{
							LOG.warn("Unknown signal:"+lbl);
						}
					}
				}
				
			}else if (message==SignalMessage.BEGIN) {
				clearData(clearingDataWhenBeginMessage_);
			}else if (message==SignalMessage.END) {
				LOG.debug("got END message.");
			}
		}

		private void processLabelMessage(LabelSignalMessage lbl) {
			//LOG.debug("SpectrogramView: labelSig "+lbl);
			synchronized(labelData_) {
				labelData_.add(lbl);
				requestUpdateTimeRangeAndRedraw();
				//requestRedraw();
			}
		}

		private void processVectorSignalMessage(VectorSignalMessage we) {
			synchronized(waveData_) {
				waveData_.add(we);
				requestUpdateTimeRangeAndRedraw();
				//requestRedraw();
			}
		}
	};
	
	void setVectorData(Collection<VectorSignalMessage> waveData) {
		synchronized(waveData_) {
			waveData_.clear();
			waveData_.addAll(waveData);
			requestUpdateTimeRangeAndRedraw();
		}
	}
	
	void setLabelData(Collection<LabelSignalMessage> labelData) {
		synchronized(labelData_) {
			labelData_.clear();
			labelData_.addAll(labelData);
			requestUpdateTimeRangeAndRedraw();
		}
	}

	public MessageProcessor getInputPort() { return inputPort_; }
	
	public static final int DATA_BIT_LABEL=2;
	public static final int DATA_BIT_WAVE=1;
	public static final int DATA_BITS_ALL=DATA_BIT_LABEL|DATA_BIT_WAVE;
	
	private int clearingDataWhenBeginMessage_=DATA_BITS_ALL;
	
	public void clearData(int dataToClear) {
		if ((dataToClear&DATA_BIT_LABEL)!=0) {
			synchronized (labelData_) {
				labelData_.clear();
			}
		}
		if ((dataToClear&DATA_BIT_WAVE)!=0) {
			synchronized(waveData_) {
				waveData_.clear();
				waveDataTimeMin_=0;
				waveDataTimeMax_=0;
				//viewTimeMax_=0;
				requestUpdateTimeRangeAndRedraw();
			}
		}
	}

	public int getSignalDataCapacity() {
		return signalDataCapacity_;
	}

	public void setSignalDataCapacity(int signalDataCapacity) {
		signalDataCapacity_ = signalDataCapacity;
	}

	public long getViewTimeWidth() {
		return viewTimeWidth_;
	}

	public void setViewTimeWidth(long viewTimeWidth) {
		viewTimeWidth_ = viewTimeWidth;
	}

	public double getValueMin() {
		return valueMin_;
	}

	public void setValueMin(double valueMin) {
		valueMin_ = valueMin;
	}

	public double getValueHeight() {
		return valueHeight_;
	}

	public void setValueHeight(double valueHeight) {
		valueHeight_ = valueHeight;
	}

	public boolean isShowScale() {
		return showScale_;
	}

	public void setShowScale(boolean showGraduations) {
		showScale_ = showGraduations;
	}
	
	public void setTitleName(String s) {
		topLabel_.setText(s);
	}

	public boolean isFollowSlider() {
		return followSlider_;
	}

	public void setFollowSlider(boolean followSlider) {
		followSlider_ = followSlider;
	}

	public long getViewTimeMax() {
		return viewTimeMax_;
	}

	public void setViewTimeMax(long viewTimeMax) {
		viewTimeMax_ = viewTimeMax;
		//
		if (viewTimeMax_<waveDataTimeMin_+viewTimeWidth_) viewTimeMax_=waveDataTimeMin_+viewTimeWidth_;
		if (viewTimeMax_>waveDataTimeMax_) viewTimeMax_=waveDataTimeMax_;
		//
		if (!slider_.isDisposed()) {
			slider_.setSelection((int)((viewTimeMax_-waveDataTimeMin_)/sliderUnitTime_)-slider_.getThumb());
		}
	}
	
	public long getViewTimeMin() {
		return viewTimeMax_ - viewTimeWidth_;
	}
	
	public void setViewTimeMin(long viewTimeMin) {
		setViewTimeMax(viewTimeMin+viewTimeWidth_);
	}

	public ToolBar getToolBar() {
		return toolBar_;
	}

	public Long getTimeMarkerBegin() {
		return timeMarkerBegin_;
	}

	public Long getTimeMarkerEnd() {
		return timeMarkerEnd_;
	}

	public int getClearingDataWhenBeginMessage() {
		return clearingDataWhenBeginMessage_;
	}

	public void setClearingDataWhenBeginMessage(int clearDataWhenBeginMessage) {
		clearingDataWhenBeginMessage_ = clearDataWhenBeginMessage;
	}
	
	public void setFrequency(double frequency) {
		frequency_ = frequency;
	}
}
