package initTag;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.*;

import com.uhf.api.cls.Reader;
import com.uhf.api.cls.Reader.AntPower;
import com.uhf.api.cls.Reader.AntPowerConf;
import com.uhf.api.cls.Reader.Inv_Potl;
import com.uhf.api.cls.Reader.Inv_Potls_ST;
import com.uhf.api.cls.Reader.Lock_Obj;
import com.uhf.api.cls.Reader.Lock_Type;
import com.uhf.api.cls.Reader.Mtr_Param;
import com.uhf.api.cls.Reader.READER_ERR;
import com.uhf.api.cls.Reader.Region_Conf;
import com.uhf.api.cls.Reader.SL_TagProtocol;
import com.uhf.api.cls.Reader.TAGINFO;
import com.uhf.api.cls.Reader.TagFilter_ST;


public class InitTagWrite extends JFrame {
	private JTextField port;
	private JComboBox<Integer> antcount;
	private JTextField accpwd;
	private JTextField killpwd;
	private JTextField selantenna;
	private JTextField epc;
	private JTextField writeData;
	private JTextField bank;
	private JTextField address;
  
   	public InitTagWrite(int h, int w) { 
		super();
	   
		Container coter = this.getContentPane();
		this.setLayout(null);
		
		/*
		 * Initialize the tag's access password, kill password, and EPC code, and lock 
		 * the tag's access password, kill password, and EPC area. 
		 * Note: In the actual application scenario, it is often necessary to lock these storage 
		 * areas after starting the EPC area or USER area of the tag to prevent unauthorized rewriting. 
		 * If it is such an application, the access password of the tag must be initialized 
		 * to be non-zero to lock the other storage area of the tag. If it is considered 
		 * that the tag may need to be killed in the future, the tag's kill password must 
		 * also be initialized. Access password and kill password also need to be locked, 
		 * and these passwords cannot be read and rewritten without authorization.
		 */
		JButton jbt1 = new JButton("Initialize Tags");
		jbt1.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				if (!PreTagOp())
					return;
			
				String acpwd = accpwd.getText();
				byte[] acpwdb = new byte[4];
				rdr.Str2Hex(acpwd, acpwd.length(), acpwdb);
				
				String klpwd = killpwd.getText();
				byte[] klpwdb = new byte[4];
				rdr.Str2Hex(klpwd, klpwd.length(), klpwdb);
				
				// Initialize the EPC code to be written
				String sepc = epc.getText();
				byte[] wepc = new byte[sepc.length()/2];
				rdr.Str2Hex(sepc, sepc.length(), wepc);

				// Setting the accesspwd parameter to NULL is equivalent to passing an access password of all 0s.
				READER_ERR err = rdr.WriteTagEpcEx(Integer.parseInt(selantenna.getText()), wepc, sepc.length()/2, null, (short) 1000);
				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());
					return;
				}
				
				err = rdr.WriteTagData(Integer.parseInt(selantenna.getText()), (char) 0, 0, klpwdb, 4, null, (short) 1000);
				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());
					return;
				}
				
				err = rdr.WriteTagData(Integer.parseInt(selantenna.getText()), (char) 0, 2, acpwdb, 4, null, (short) 1000);
				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());
					return;
				}
				
				//Lock kill password, access password and EPC area
				byte bt = (byte)(Lock_Obj.LOCK_OBJECT_KILL_PASSWORD.value() |  Lock_Obj.LOCK_OBJECT_ACCESS_PASSWD.value() | Lock_Obj.LOCK_OBJECT_BANK1.value());
				short st = (short)(Lock_Type.KILL_PASSWORD_LOCK.value() | Lock_Type.ACCESS_PASSWD_LOCK.value() | Lock_Type.BANK1_LOCK.value());
				err = rdr.LockTag(Integer.parseInt(selantenna.getText()), bt, st, acpwdb, (short) 1000);
				
				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());
					return;
				} else {
					// Because the current tag is set as the filter condition before the operation, 
					// the filter condition should be removed after the operation is successful, 
					// otherwise it will affect the number of tags detected in the antenna field 
					// before the next tag operation.
					rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, null);
					MessageBox("Operation successful");
					return;
				}
			}
	   	});
	   
	   
		/*
		 * Write the EPC code to the tag. 
		 * In this example, the data represented by the hexadecimal string 000000000000000000000001 
		 * is written into the EPC area. However, please note that both the WriteTagEpcEx and 
		 * WriteTagData methods can modify the data in the EPC area of ​​the tag. There are several 
		 * bits in the PC segment of the EPC area that are used to indicate the length of the EPC 
		 * code returned to the reader when performing an inventory operation (corresponding to the 
		 * read method). In other words, the length of the returned EPC code can be less than or 
		 * equal to the actual EPC bank capacity. The WriteTagEpcEx method will write data to the 
		 * EPC area starting from block address 2. At the same time, the bit indicating the length 
		 * of the EPC code for the inventory operation in the PC segment is set to the length of the 
		 * written data. That is, the data written by the WriteTagEpcEx method will be exactly the 
		 * same as the data read by the Read method. The WriteTagData method can modify any writable 
		 * storage bank in the EPC bank.
		 */
		JButton jbt2 = new JButton("Write EPC");
		jbt2.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				if (!PreTagOp())
					return; 
				
				// When the tag leaves the factory, the access password is all 0. 
				// If the tag has already been locked, set the access password according to the actual situation.
				String pwd = accpwd.getText();
				byte[] pwdb = new byte[4];
				rdr.Str2Hex(pwd, pwd.length(), pwdb);
					     			     
			    // Initialize the EPC code to be written
				String sepc = epc.getText();
				byte[] wepc = new byte[(int) sepc.length()/2];
				rdr.Str2Hex(sepc, sepc.length(), wepc);

				// The timeout period is set to 1000 ms for EPC code writing operations, meaning that 
				// the operation will block for at most 1000 ms.
				// If the operation is completed within the timeout period or if there is an error, 
				// it will return early
				READER_ERR err = rdr.WriteTagEpcEx(Integer.parseInt(selantenna.getText()), wepc, wepc.length, pwdb, (short)1000);

				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());
					 
				} else {
					// Because the current tag is set as the filter condition before the operation, 
					// the filter condition should be removed after the operation is successful, 
					// otherwise it will affect the number of tags detected in the antenna field 
					// before the next tag operation.
					rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, null);
					MessageBox("Operation successful");
					return;
				}
			}
		});

		/*
		 * Write data to the tag storage area.
		 */
		JButton jbt3 = new JButton("Write memory");
		jbt3.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				if (!PreTagOp())
					return; 
				
				// There are two cases for setting the access password:
				// 1. When the operating bank is locked, you must set the access password that is 
				//    consistent with the tag to succeed
				// 2. When the operating bank is not locked, you can set the password to 0, or do 
				//    not set the access password (null).
				// The reader uses 0 as the access password by default
				
				// When the tag leaves the factory, the access password is all 0. 
				// If the tag has already been locked, set the access password according to the actual situation.
				// Set the access password
				String pwd = accpwd.getText();
				byte[] accesspwd = new byte[4];
				rdr.Str2Hex(pwd, pwd.length(), accesspwd);

				String data = writeData.getText();
				byte[] wdata = new byte[4];
				rdr.Str2Hex(data, data.length(), wdata);
				// The timeout period is set to 1000 ms for EPC code writing operations, meaning that 
				// the operation will block for at most 1000 ms.
				// If the operation is completed within the timeout period or if there is an error, 
				// it will return early
				READER_ERR err = rdr.WriteTagData(
						Integer.parseInt(selantenna.getText()), 
						(char) Integer.parseInt(bank.getText()), 
						Integer.parseInt(address.getText()), 
						wdata, 4, accesspwd, (short)1000);
				
				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());
					 
				} else {
					// Because the current tag is set as the filter condition before the operation, 
					// the filter condition should be removed after the operation is successful, 
					// otherwise it will affect the number of tags detected in the antenna field 
					// before the next tag operation.
					rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, null);
					MessageBox("Operation successful");
					return;
				}
			}
	   	});
	   
	   
		/*
		 * Read the data in the tag storage area.
		 */
		JButton jbt4 = new JButton("Read memory");
		jbt4.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				if (!PreTagOp())
					return;
				
				// When the tag leaves the factory, the access password is all 0. 
				// If the tag has already been locked, set the access password according to the actual situation.
				String pwd = accpwd.getText();
				byte[] accesspwd = new byte[4];
				rdr.Str2Hex(pwd, pwd.length(), accesspwd);
				
				// The timeout period is set to 1000 ms for EPC code writing operations, meaning that 
				// the operation will block for at most 1000 ms.
				// If the operation is completed within the timeout period or if there is an error, 
				// it will return early
				int len = 2;
				byte[] rdata = new byte[len*2];
				// Reading EPC
				READER_ERR err = rdr.GetTagData(
						Integer.parseInt(selantenna.getText()), 
						(char) Integer.parseInt(bank.getText()), 
						Integer.parseInt(address.getText()),
						len, rdata, accesspwd, (short)1000);
				
				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());	 
				} else {
					// Because the current tag is set as the filter condition before the operation, 
					// the filter condition should be removed after the operation is successful, 
					// otherwise it will affect the number of tags detected in the antenna field 
					// before the next tag operation.
					rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, null);
					MessageBox("Operation successful");
					// Print as hex
					StringBuilder sb = new StringBuilder();
					for (byte b : rdata) 
						sb.append(String.format("%02x", b));
					MessageBox(sb.toString());
					return;
				}
			}
	   	});

		/*
		 * Lock the tag storage areas. 
		 * In this example, the EPC bank of ​​the tag is temporarily locked.
		 * It should be noted that before locking the tag storage bank, it is generally necessary to 
		 * initialize the tag access password to non-zero, otherwise the operation will fail. 
		 * Initializing the tag access password can be operated through the WriteTagData method.
		 */
		JButton jbt5 = new JButton("Lock Tag");
		jbt5.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				if (!PreTagOp())
					return;

				String pwd = accpwd.getText();
				byte[] accesspwd = new byte[4];
				rdr.Str2Hex(pwd, pwd.length(), accesspwd);
				
				// The timeout period is set to 1000 ms for EPC code writing operations, meaning that 
				// the operation will block for at most 1000 ms.
				// If the operation is completed within the timeout period or if there is an error, 
				// it will return early
				READER_ERR err = rdr.LockTag(Integer.parseInt(selantenna.getText()), (byte)(Lock_Obj.LOCK_OBJECT_BANK1.value()), (byte)(Lock_Type.BANK1_LOCK.value()), accesspwd, (short)1000);
				
				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());
					 
				} else {
					// Because the current tag is set as the filter condition before the operation, 
					// the filter condition should be removed after the operation is successful, 
					// otherwise it will affect the number of tags detected in the antenna field 
					// before the next tag operation.
					rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, null);
					MessageBox("Operation successful");
					return;
				}
			}
		});
	   
		/*
		 * Kill the tag. Once the tag is killed, it can no longer be used.
		 * It should be noted that the tag can only be killed if it is initialized with a 
		 * non-zero kill password.
		 */
		JButton jbt6 = new JButton("Kill Tags");
		jbt6.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				if (!PreTagOp())
					return;

				String pwd = killpwd.getText();
				byte[] killpwd = new byte[4];
				rdr.Str2Hex(pwd, pwd.length(), killpwd);
				
				// The timeout period is set to 1000 ms for EPC code writing operations, meaning that 
				// the operation will block for at most 1000 ms.
				// If the operation is completed within the timeout period or if there is an error, 
				// it will return early
				READER_ERR err = rdr.KillTag(Integer.parseInt(selantenna.getText()), killpwd, (short) 1000);
				
				if (err != READER_ERR.MT_OK_ERR) {
					MessageBox("Operation failed, error code: " + err.toString());
					 
				} else {
					// Because the current tag is set as the filter condition before the operation, 
					// the filter condition should be removed after the operation is successful, 
					// otherwise it will affect the number of tags detected in the antenna field 
					// before the next tag operation.
					rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, null);
					MessageBox("Operation successful");
					return;
				}
			}
		});
		
		JButton btnConnect = new JButton("Connect");
		btnConnect.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				OpenReader();
			}
		});
	   
		
		port = new JTextField("192.168.10.99", 20);
		JLabel portLabel = new JLabel("Port");
		portLabel.setLabelFor(port);
		
		Integer[] antCounts = new Integer[] {1, 2, 4, 8, 16};
		antcount = new JComboBox<Integer>(antCounts);
		JLabel countLabel = new JLabel("Number of possible antennas");
		countLabel.setLabelFor(antcount);
		
		accpwd = new JTextField("00000000");
		JLabel accLabel = new JLabel("Access password (hex)");
		accLabel.setLabelFor(accpwd);
		
		killpwd = new JTextField("00000000");
		JLabel killLabel = new JLabel("Kill password (hex)");
		killLabel.setLabelFor(killpwd);
		
		selantenna = new JTextField("1");
		JLabel selAntLabel = new JLabel("Operating antenna");
		selAntLabel.setLabelFor(selantenna);
		
		epc = new JTextField("012345678901234567890129");
		JLabel epcLabel = new JLabel("EPC (hex)");
		epcLabel.setLabelFor(epc);
		
		bank = new JTextField("1");
		JLabel bankLabel = new JLabel("Bank to be written/read");
		bankLabel.setLabelFor(bank);
		
		writeData = new JTextField("");
		JLabel dataLabel = new JLabel("Data to be written (4 Byte)");
		dataLabel.setLabelFor(writeData);
		
		address = new JTextField("2");
		JLabel addrLabel = new JLabel("Data address to be written/read");
		addrLabel.setLabelFor(address);
		
		
		int x = 50, y = 60;
		int xw = 200, yh = 50;
		btnConnect.setBounds(x, y, xw, yh);
		jbt1.setBounds(x, y*2, xw, yh);
		jbt2.setBounds(x, y*3, xw, yh);
		jbt3.setBounds(x, y*4, xw, yh);
		jbt4.setBounds(x, y*5, xw, yh);
		jbt5.setBounds(x, y*6, xw, yh);
		jbt6.setBounds(x, y*7, xw, yh);
		x = 300;
		y = 30;
		yh = 25;
		portLabel.setBounds(x, y, xw, yh);
		port.setBounds(x, y*2, xw, yh);
		countLabel.setBounds(x, y*3, xw, yh);
		antcount.setBounds(x, y*4, xw, yh);
		selAntLabel.setBounds(x, y*5, xw, yh);
		selantenna.setBounds(x, y*6, xw, yh);
		accLabel.setBounds(x, y*7, xw, yh);
		accpwd.setBounds(x, y*8, xw, yh);
		killLabel.setBounds(x, y*9, xw, yh);
		killpwd.setBounds(x, y*10, xw, yh);
		epcLabel.setBounds(x, y*11, xw, yh);
		epc.setBounds(x, y*12, xw, yh);
		bankLabel.setBounds(x, y*13, xw, yh);
		bank.setBounds(x, y*14, xw, yh);
		addrLabel.setBounds(x, y*15, xw, yh);
		address.setBounds(x, y*16, xw, yh);
		dataLabel.setBounds(x, y*17, xw, yh);
		writeData.setBounds(x, y*18, xw, yh);
		
		coter.add(btnConnect);
		coter.add(jbt1);
		coter.add(jbt2);
		coter.add(jbt3);
		coter.add(jbt4);
		coter.add(jbt5);
		coter.add(jbt6);
		coter.add(portLabel);
		coter.add(countLabel);
		coter.add(accLabel);
		coter.add(killLabel);
		coter.add(selAntLabel);
		coter.add(epcLabel);
		coter.add(bankLabel);
		coter.add(dataLabel);
		coter.add(addrLabel);
		coter.add(port);
		coter.add(antcount);
		coter.add(selantenna);
		coter.add(accpwd);
		coter.add(killpwd);
		coter.add(epc);
		coter.add(bank);
		coter.add(writeData);
		coter.add(address);
		
		
		this.setSize(w, h);
		this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		this.setVisible(true);
		
		if (OpenReader() != READER_ERR.MT_OK_ERR) {   
			MessageBox("Failed to initialize the reader/writer. Please check the device address and type and reopen it.");
			return;
		}
		
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				if (rdr != null)
					rdr.CloseReader();
				System.exit(0);
			}
		});
   	}
   
	Reader rdr = null;
	READER_ERR OpenReader() {
		// Initialize the reader/writer instance
		// When connecting using the device's network port, the second parameter of the 
		// InitReader_Notype function may also be an IP address
		rdr = new Reader();
		READER_ERR er = rdr.InitReader_Notype(port.getText(), (int)antcount.getSelectedItem());
		if (er != READER_ERR.MT_OK_ERR)
			return er;
			
		/* Required parameters */

		// Set the reader's read power to 24dbm and the write power to 27dbm. 
		// For initialization tag applications, it is not advisable to set the transmit power too 
		// high. Generally speaking, the greater the transmit power, the farther the read/write 
		// distance.
		AntPowerConf apcf = rdr.new AntPowerConf();
		apcf.antcnt = (int)antcount.getSelectedItem();
		for (int i = 0; i < apcf.antcnt; i++) {
			AntPower jaap = rdr.new AntPower();
			jaap.antid = i+1;
			jaap.readPower = 2400;
			jaap.writePower = 2700;
			apcf.Powers[i] = jaap; 
		}
		// 
		rdr.ParamSet(Mtr_Param.MTR_PARAM_FREQUENCY_REGION, Region_Conf.RG_EU3);
			
		// Set the antennas configuration.
		er = rdr.ParamSet(Mtr_Param.MTR_PARAM_RF_ANTPOWER, apcf);
		if (er != READER_ERR.MT_OK_ERR)
			return er;
		
		// Set the reader to execute the GEN2 air interface protocol  
		Inv_Potls_ST ipst = rdr.new Inv_Potls_ST();
		ipst.potlcnt = 1;
		ipst.potls = new Inv_Potl[1];
		for (int i = 0; i < ipst.potlcnt; i++) {
			Inv_Potl ipl = rdr.new Inv_Potl();
			ipl.weight = 30;
			ipl.potl = SL_TagProtocol.SL_TAG_PROTOCOL_GEN2;
			ipst.potls[0] = ipl;
		}
		
		er = rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_INVPOTL, ipst);
		return er;
	}
   
	void MessageBox(String mes) {
		JOptionPane.showMessageDialog(null, mes, "Notification", JOptionPane.INFORMATION_MESSAGE);
	}

	// Used to detect whether there is only one tag in the antenna field before a specific tag 
	// operation, and set the tag's EPC code as the filter condition for subsequent tag operations
	boolean PreTagOp() {
		int[] tagcnt = new int[1];
		TAGINFO taginfo = rdr.new TAGINFO();
		READER_ERR err = rdr.TagInventory_Raw(new int[]{Integer.parseInt(selantenna.getText())}, 1, (short)300, tagcnt);
		if (err != READER_ERR.MT_OK_ERR) {
			MessageBox("Inventory failed, error code: " + err.toString());
			return false;
		}
		if (tagcnt[0] != 1) {
			MessageBox("Please ensure that there is only one tag in the antenna field: " + tagcnt[0]);
			return false;
		}
		// Get the EPC code of the unique tag in the current antenna field
		err = rdr.GetNextTag(taginfo);
		if (err != READER_ERR.MT_OK_ERR) {
			MessageBox("Failed to obtain tag, error code: " + err.toString());
			return false;
		}
		// Set the tag's EPC code as the filter condition for future tag operations
		TagFilter_ST tfst = rdr.new TagFilter_ST();
		tfst.bank = 1;
		tfst.fdata = taginfo.EpcId;
		tfst.flen = taginfo.Epclen*8;
		tfst.isInvert = 0;
		tfst.startaddr = 32;
		
		err = rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, tfst);
		return true;
	}
 
	public static void main(String[] args) {
		System.out.println(System.getProperty("java.library.path"));
			String arch = System.getProperty("os.arch"); 
			String os= System.getProperty("os.name");

			System.out.println(arch); 
			System.out.println(os);
			try {
				if (!System.getProperty("os.arch").contains("64")) { 
					// 32-bit systems require this support library
					System.loadLibrary("ACE");
				}
				System.loadLibrary("PCOMM");
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		
		System.out.println("inittagwrite sample for java");
		InitTagWrite fm = new InitTagWrite(640, 640);
	}
}
