package jbCAP;

import jVARIANT.VARIANT;
import jVARIANT.VARENUM;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/** @file bCapSocketUDP.java
 *
 *  @brief b-CAP client library
 *
 *  @version	1.2
 *	@date		2014/5/26
 *	@author		DENSO WAVE (m)
 *
 */
class bCapSocketUDP extends bCapSocket implements Runnable{
	private InetSocketAddress m_addr;
	private DatagramSocket m_sock;
	
	private short m_sSerial;
	private int m_retry;
	
	private static final int m_iPackSize = 504;
	
	private bCapPacket m_msg;
	private bCapPacket m_msgRet;
	
	private static bCapConverter UDPConverter = new bCapConverter(0);
	
	protected bCapSocketUDP(String host, int port, int timeout, int retry, int wdt)
	{

		m_addr = new InetSocketAddress(host, port);
		
		try
		{
			m_sock = new DatagramSocket();
			
			if(timeout < 0)
			{
				m_sock.setSoTimeout(0);
			}
			else
			{
				m_sock.setSoTimeout(timeout);
			}
			
			m_sSerial = 1;
			
			if(retry < 1)
			{
				m_retry = 1;
			}
			else if(7 < retry)
			{
				m_retry = 7;
			}
			else
			{
				m_retry = retry;
			}
						
			if(wdt >= 80){
				bCapStart(new VARIANT(VARENUM.VT_BSTR, ",WDT=" + Integer.toString(wdt)));
			}else{
				bCapStart(null);
			}
		}
		catch(Throwable ex)
		{
			Release();
		}
		
	}
	
	@Override
	protected void Release()
	{
		bCapStop();
		
		if(m_sock != null)
		{
			m_sock.close();
			m_sock = null;
		}
		
		m_addr = null;
	}
	
	@Override
	protected int IsConnected()
	{
		if(m_addr == null)
		{
			return E_NOT_CONNECTED;
		}
		else
		{
			return 0;
		}
	}
	
	@Override
	protected synchronized bCapPacket SendMessage(bCapPacket msg)
	{
		m_msg = msg;
		m_msgRet = null;
		
		Thread th = new Thread(this);
		
		th.start();
		WaitThread(th);
		
		return m_msgRet;
	}
	
	public void run(){
		boolean bExit = false;
		byte[] bSend, bReceive = new byte[m_iPackSize];
		m_msgRet = new bCapPacket();

		m_msg.m_Reserv = m_sSerial;
		
		try {
			bSend = UDPConverter.Encode(m_msg);
		}catch(Throwable e){
			m_msgRet = ReturnErrorPacket(e);
			return;
		}
		
		for(int iCount = 0; iCount < m_retry; iCount++)
		{
			try
			{
				// Send Message
				m_msg.m_Serial = m_sSerial;
				UDPConverter.SetSerial(bSend, m_sSerial);
				m_sock.send(new DatagramPacket(bSend, bSend.length, m_addr));

				do{
					// Receive Message
					m_sock.receive(new DatagramPacket(bReceive, m_iPackSize));

					// byte -> bCapPacket
					m_msgRet = UDPConverter.Decode(bReceive);
					
					if(m_msg.m_Serial != m_msgRet.m_Serial){
						continue;
					}
					
					if(m_msgRet.m_ID != S_EXECUTING){
						break;
					}
				}while(true);
				
				bExit = true;
			}
			catch(Throwable e)
			{
				if(m_retry - 1 <= iCount)
				{
					m_msgRet = ReturnErrorPacket(e);
					bExit = true;
				}
			}
			finally
			{
				m_sSerial = (short)((m_sSerial != -1) ? m_sSerial + 1 : 1);
				if(bExit) return;
			}
		}
	}
}
