package com.sap.dbmtk.demo;

import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;

import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextScrollPane;

import com.sap.dbmtk.demo.utils.SwingUtils;
import com.sap.dbmtk.demo.utils.TimeUtils;

import net.miginfocom.swing.MigLayout;

public class SqlTraceWindow 
extends JFrame
{
//	private static Logger        _logger          = Logger.getLogger(SqlTraceWindow.class);
	private static final long    serialVersionUID = 1L;
	
	private static SqlTraceWindow _instance       = null;

//	private JFrame _owner = null;
	
	private RSyntaxTextArea _log_txt      = new RSyntaxTextArea(50, 100);
	private RTextScrollPane _log_sp        = new RTextScrollPane(_log_txt);
	private JCheckBox       _moveToEnd_chk = new JCheckBox("Move To End", true);
	private JButton         _close_but     = new JButton("Close");

	private String          _dbmsProductName = "UNKNWON";

	private long            _execStartTime = 0; // used for tracing execution time... we can add a HashList with "label" if we want several timers

	private SimpleDateFormat _sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public SqlTraceWindow()
	{
		super();
		init();
		pack();
	}

	private void init()
	{
		ImageIcon icon16 = SwingUtils.readImageIcon(DemoApp.class, "images/sql_16.png");
		ImageIcon icon32 = SwingUtils.readImageIcon(DemoApp.class, "images/sql_32.png");

		ArrayList<Image> iconList = new ArrayList<Image>();
		if (icon16 != null) iconList.add(icon16.getImage());
		if (icon32 != null) iconList.add(icon32.getImage());
		setIconImages(iconList);

		_log_txt.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);

		setLayout(new MigLayout("insets 0 0 0 0"));
		add(_log_sp,         "grow, push, wrap 20");
		add(_moveToEnd_chk,  "split");
		add(_close_but,      "tag ok, wrap");
		
		_close_but.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				_instance.setVisible(false);
			}
		});
	}

	public void open()
	{
		_instance.setVisible(true);
	}

	public static SqlTraceWindow getInstance()
	{
		if (_instance == null)
			_instance = new SqlTraceWindow();

		return _instance;
	}

	public static boolean hasInstance()
	{
		return (_instance != null);
	}

	public static void setInstance(SqlTraceWindow inst)
	{
		_instance = inst;
	}


	public void setDatabaseProductName(String dbmsProductName)
	{
		_dbmsProductName = dbmsProductName;
	}

	public void addSql(String sql)
	{
		StringBuilder sb = new StringBuilder();
		String timeNow = _sdf.format(new Date(System.currentTimeMillis()));

//		final StackTraceElement[] ste = new Throwable().getStackTrace();
////		StackTraceElement element = ste[1];
//		StackTraceElement element = ste[2];
		
//new Exception("").printStackTrace();
//StringUtil.stackTraceToString(new Exception("DUMMY EXCEPTION"));

		sb.append("\n");
		sb.append("\n");
		sb.append("/*========================================================================================*\n");
		sb.append(" * Time: ").append(timeNow).append("\n");
//		sb.append(" * At:   ").append(element).append("\n");
		sb.append(" * DBMS: ").append(_dbmsProductName).append("\n");
//sb.append(StringUtil.stackTraceToString(new Exception("DUMMY EXCEPTION"))).append("\n");

		sb.append(" *========================================================================================*/\n");
		sb.append(sql);

		if ( ! sql.endsWith("\n") )
			sb.append("\n");

		append(sb.toString());
	}

	public void addException(Throwable ex)
	{
		StringBuilder sb = new StringBuilder();

		String msg = ""+ex;
		if (ex instanceof SQLException)
			msg = SqlStatement.getSqlMessages((SQLException)ex, null);

		sb.append("------------------------------------------------------\n");
		sb.append("-- Exception -----------------------------------------\n");
		sb.append("------------------------------------------------------\n");
		sb.append(ex);
//		sb.append("\n");
		sb.append("Decoded message: \n").append(msg);
		sb.append("\n");
		
		append(sb.toString());
	}

	public void addRowcount(int rowCount)
	{
		StringBuilder sb = new StringBuilder();

		sb.append("-- >>>>> ROWS Affected = ").append(rowCount).append(" <<<<< --\n");
		
		append(sb.toString());
	}

	public void addParam(int p, SqlStatementParam param)
	{
		StringBuilder sb = new StringBuilder();

		sb.append("-- ").append(p).append(": ").append(param).append("\n");
		
		append(sb.toString());
	}
	
	public void addParamAfterExec(int p, SqlStatementParam param)
	{
		StringBuilder sb = new StringBuilder();

		sb.append("-- OUTPUT VALUE: ").append(p).append(": ").append(param).append("\n");

		append(sb.toString());
	}

	/**
	 * Add a row <code>-- EXEC TIME: %SS.%ms   label='labelText'</code>
	 * 
	 * @param execTime the time difference in milliseconds
	 * @param labelText a label so we know what the timing is all about
	 */
	public void addExecTime(long execTime, String labelText)
	{
		StringBuilder sb = new StringBuilder();

		sb.append("-- EXEC TIME: ").append(TimeUtils.msToTimeStr("%SS.%ms", execTime)).append("   label='").append(labelText).append("'.\n");

		append(sb.toString());
	}

	/**
	 * Set internal variable to "now, later get the time difference and report it using  reportTime()
	 */
	public void startTimer()
	{
		_execStartTime = System.currentTimeMillis();
	}

	/**
	 * report the difference in ms since we last called startTimer()<br>
	 * The report is printed via method addExecTime(long execTime, String labelText)
	 * 
	 * @param labelText a label so we know what the timing is all about
	 * @return the timeDiff
	 */
	public long reportTime(String labelText)
	{
		long execTime = System.currentTimeMillis() - _execStartTime;
		addExecTime(execTime, labelText);
		return execTime;
	}
	
	private void append(String txt)
	{
//		System.out.print(txt);
		_log_txt.append(txt);

		if (_moveToEnd_chk.isSelected())
		{
			_log_txt.setCaretPosition( _log_txt.getDocument().getLength() );
		}
	}
}
