package nl.nikhef.safaripark;

import java.awt.Component;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

import nl.nikhef.safaripark.devmgr.BaySelectionListener;
import nl.nikhef.sfp.SFPDevice;
import nl.nikhef.sfp.ddmi.DDMI;
import nl.nikhef.sfp.ddmi.DDMIContext;
import nl.nikhef.sfp.ddmi.DDMILoader;
import nl.nikhef.sfp.ddmi.DataSource;
import nl.nikhef.tools.Utils;


public class ModuleManager implements BaySelectionListener 
{
	
	private Action _binExport;
	private JFileChooser _dirChooser;
	private JRadioButton _binary;
	private JRadioButton _plainhex;
	private JRadioButton _extendedhex;
	
	private DDMI _ddmi;
	private ContextCache _ctxCache;
	private DDMIContext _ctx;
	private String _moduleName;
	private DateFormat _fileDateFormat = new SimpleDateFormat("yyMMdd_HHmmss");

	public ModuleManager(Action binExport, DDMILoader ddmiLoader, ContextCache cc) 
	{
		_ctxCache = cc;
		_binExport = binExport; 
		_binExport.setEnabled(false);
		_dirChooser = new JFileChooser();
		
		
		_ddmi = ddmiLoader.getDDMI();
		
		ButtonGroup bg = new ButtonGroup();
		_binary = new JRadioButton("Binary");
		_plainhex = new JRadioButton("Plain Hex");
		_extendedhex = new JRadioButton("Extended Hex");
		bg.add(_plainhex);
		bg.add(_extendedhex);
		bg.add(_binary);
		_extendedhex.setSelected(true);

		JPanel pnl = new JPanel();
		pnl.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
		pnl.setLayout(new BoxLayout(pnl, BoxLayout.PAGE_AXIS));		
		pnl.add(new JLabel("Export format"));
		pnl.add(_extendedhex);
		pnl.add(_plainhex);
		pnl.add(_binary);
		
		_dirChooser.setAccessory(pnl);
		
		_dirChooser.setDialogTitle("Select directoy to export module contents to");
		_dirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
	}

	@Override
	public void baySelected(SFPDevice dev, int bay) {
		try {
			if (dev.isModulePresent(bay)) 
			{
				_ctx = _ctxCache.getContextFor(dev, bay);
				
				_moduleName = dev.getModuleSerial(bay);
				_binExport.setEnabled(true);
			} else {
				_ctx = null;
				_binExport.setEnabled(false);
			}
		} catch (IOException e) {
			_ctx = null;
			_binExport.setEnabled(false);
		}

	}
	
	public void exportBinary(Component parent)
	{
		if ((_dirChooser.showDialog(parent, "Select") != JFileChooser.APPROVE_OPTION)) 
		{
			return;
		}
		
		File f = _dirChooser.getSelectedFile();
		
		
		
		
		for (DataSource ds : _ddmi.getSources()) 
		{
			if (!ds.isValid(_ctx)) continue;
			System.out.println("Exporting datasource " + ds);
	
			try {

				byte[] data = ds.read(_ctx, ds.start, ds.size());
				String filebase = String.format("sfp_%s_%s_%s",
						 _fileDateFormat.format(new Date()),
						 _moduleName,
						 ds.getPath());
				
				
				
				
				if (_plainhex.isSelected()) {
					exportHex(f, filebase, data, false);	
				}
				if (_binary.isSelected()) {
					exportBinary(f, filebase, data);
				}
				if (_extendedhex.isSelected()) {
					exportHex(f, filebase, data, true);
				}

			} catch (IOException e) {
				e.printStackTrace();
				continue;
			}
			
		}
		
	
	}

	
	
	private void exportHex(File f, String filebase, byte[] content, boolean extended) throws IOException 
	{
		PrintWriter pw = new PrintWriter(new FileWriter(new File(f, filebase + (extended ? ".txt" : ".hex"))));
		try {
			Utils.dumpHex(pw, content, extended);
		} finally {
			pw.close();
		}
	}


	private void exportBinary(File f, String filebase, byte[] content) throws IOException 
	{
		FileOutputStream fos = new FileOutputStream(new File(f, filebase + ".bin"));
		try {
			fos.write(content);
		} finally {
			fos.close();
		}
	}
	
	@Override
	public boolean canSelectBay(SFPDevice dev, int bay) {
		return true;
	}

}
