package com.atid.app.atx.usb.storeddata.adapter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;

import com.atid.app.atx.usb.storeddata.R;
import com.atid.lib.module.barcode.types.BarcodeType;
import com.atid.lib.util.diagnotics.ATLog;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class DataListAdapter extends BaseAdapter {
	private static final String TAG = DataListAdapter.class.getSimpleName();
	private static final int INFO = ATLog.L2;
	
	private static final int DATA_TYPE_RFID = 0;
	private static final int DATA_TYPE_BARCODE = 1;
	
	private LayoutInflater mInflater;
	private ArrayList<DataListItem> mList;
	private HashMap<String, DataListItem> mMap;
	
	private volatile boolean mIsDisplayPC;
	private volatile boolean mIsReportRssi;
	
	public DataListAdapter(Context context) {
		super();
		
		mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		mList = new ArrayList<DataListItem>();
		mMap = new HashMap<String, DataListItem>();
		
		mIsDisplayPC = true;
		mIsReportRssi = false;
	}
	
	public synchronized void clear() {
		mList.clear();
		mMap.clear();
		notifyDataSetChanged();
		
		ATLog.i(TAG, INFO, "INFO. clear()");
	}
	
	public synchronized void add(String tag, double rssi, double phase) {
		
		DataListItem item = null;
		
		if ( (item = mMap.get(tag)) == null ) {
			item = new DataListItem(tag, rssi, phase);
			mMap.put(tag, item);
			mList.add(item);
		} else {
			item.update(rssi, phase);
		}
		notifyDataSetChanged();
	}

	public synchronized void add(String tag, double rssi, double phase, double frequency) {

		DataListItem item = null;

		if ( (item = mMap.get(tag)) == null ) {
			item = new DataListItem(tag, rssi, phase, frequency);
			mMap.put(tag, item);
			mList.add(item);
		} else {
			item.update(rssi, phase, frequency);
		}
		notifyDataSetChanged();
	}


	public synchronized void add(BarcodeType type, String codeId, String barcode) {
		DataListItem item = null;
		
		String key = String.format(Locale.US, "%s%s%s", type, codeId, barcode);
		if ((item = mMap.get(key)) == null) {
			item = new DataListItem(type, codeId, barcode);
			mMap.put(key, item);
			mList.add(item);
		} else {
			item.update();
		}
		notifyDataSetChanged();
	}
	
	public void setDisplayPC(boolean enabled) {
		mIsDisplayPC = enabled;
		notifyDataSetChanged();		
	}
	
	public boolean getDisplayPC() {
		return mIsDisplayPC;
	}
	
	public void setReportRssi(boolean enabled) {
		mIsReportRssi = enabled;
		notifyDataSetChanged();		
	}
	
	public boolean getReportRssi() {
		return mIsReportRssi;
	}
	
	public synchronized String getData(int position) {
		return mList.get(position).getData();
	}
	
	public synchronized int getDataType(int position) {
		return mList.get(position).getDataType();
	}
	
	@Override
	public int getCount() {
		int size = 0;
		synchronized(mList) {
			size = mList.size();
		}
		return size;
	}
	
	@Override
	public Object getItem(int position) {
		DataListItem item = null;
		
		synchronized(this) {
			item = mList.get(position);
		}
		return item;
	}
	
	@Override
	public long getItemId(int position) {
		return position;
	}
	
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		DataListViewHolder holder = null;
		DataListItem item = null;
		
		if (null == convertView) {
			convertView = mInflater.inflate(R.layout.item_data_list, parent, false);
			holder = new DataListViewHolder(convertView);
		} else {
			holder = (DataListViewHolder) convertView.getTag();
		}
		
		synchronized(this) {
			item = mList.get(position);
		}
		holder.display(item);
		return convertView;
	}

	// ------------------------------------------------------------------------
	// Declare Class DataListViewHolder
	// ------------------------------------------------------------------------
	private class DataListViewHolder {
		
		private ImageView imgType;
		private LinearLayout linearTagItem;
		private LinearLayout linearBarcodeItem;
		private TextView txtBarcodeType;
		private TextView txtBarcodeId;
		private TextView txtData;
		private TextView txtRssi;
		private TextView txtPhase;
		
		private TextView txtCount;
		
		private DataListViewHolder(View parent) {
			
			imgType = (ImageView) parent.findViewById(R.id.data_type);
			linearTagItem = (LinearLayout) parent.findViewById(R.id.linear_tag_item);
			linearBarcodeItem = (LinearLayout) parent.findViewById(R.id.linear_barcode_item);
			
			txtBarcodeType = (TextView) parent.findViewById(R.id.code_type);
			txtBarcodeId = (TextView) parent.findViewById(R.id.code_id);
			txtData = (TextView) parent.findViewById(R.id.data);
			txtRssi = (TextView) parent.findViewById(R.id.rssi);
			txtPhase = (TextView) parent.findViewById(R.id.phase);
			
			txtCount = (TextView) parent.findViewById(R.id.count);
			parent.setTag(this);
		}
		
		public void display(DataListItem item) {
			if (null != item) {
				if (item.getDataType() == DATA_TYPE_RFID) {
					imgType.setImageResource(R.drawable.ic_method_rfid);
					
					linearBarcodeItem.setVisibility(View.GONE);
					txtData.setText(mIsDisplayPC ? item.getData() :
						item.getData().length() > 4 ? item.getData().substring(4) : item.getData());
					
					if (mIsReportRssi) {
						linearTagItem.setVisibility(View.VISIBLE);
						
						txtRssi.setText(String.format(Locale.US, "%.2f dB", item.getRssi()));
						txtPhase.setText(String.format(Locale.US, "%.2f \u00B0", item.getPhase()));
					} else {
						linearTagItem.setVisibility(View.GONE);
					}
				} else {
					imgType.setImageResource(R.drawable.ic_method_barcode);
					
					linearTagItem.setVisibility(View.GONE);
					txtData.setText(item.getData());
					
					linearBarcodeItem.setVisibility(View.VISIBLE);
					txtBarcodeType.setText(item.getBarocdeType().toString());
					txtBarcodeId.setText(item.getBarcodeId());
				}
				
				txtCount.setText(String.format(Locale.US, "%d", item.getCount()));
			}
		}
	}
	
	// ------------------------------------------------------------------------
	// Declare Class DataListItem
	// ------------------------------------------------------------------------
	private class DataListItem {
		private volatile int mDataType;
		private volatile String mData;
		private volatile BarcodeType mBarcodeType;
		private volatile String mBarcodeId;
		private volatile double mRssi;
		private volatile double mPhase;
		private volatile double mFrequency;
		private volatile int mCount;
		
		private DataListItem(String tag, double rssi, double phase) {
			mDataType = DATA_TYPE_RFID;
			mData = tag;
			mBarcodeId="";
			mBarcodeType = BarcodeType.Unknown;
			mRssi = rssi;
			mPhase = phase;
			mCount = 1;
		}

		private DataListItem(String tag, double rssi, double phase, double frequency) {
			mDataType = DATA_TYPE_RFID;
			mData = tag;
			mBarcodeId="";
			mBarcodeType = BarcodeType.Unknown;
			mRssi = rssi;
			mPhase = phase;
			mFrequency = frequency;
			mCount = 1;
		}

		private DataListItem(BarcodeType type, String codeId, String barcode) {
			mDataType = DATA_TYPE_BARCODE;
			mData = barcode;
			mBarcodeId = codeId;
			mBarcodeType = type;
			mRssi = 0;
			mPhase = 0;
			mCount = 1;
		}
		
		public int getDataType() {
			return mDataType;
		}
		
		public String getData() {
			return mData;
		}
		
		public BarcodeType getBarocdeType() {
			return mBarcodeType;
		}
		
		public String getBarcodeId() {
			return mBarcodeId;
		}
		
		public double getRssi() {
			return mRssi;
		}
		
		public double getPhase() {
			return mPhase;
		}

		public double getFrequency() {
			return mFrequency;
		}

		public int getCount() {
			return mCount;
		}
		
		public void update() {
			mCount++;
		}
		
		public void update(double rssi, double phase) {
			mRssi = rssi;
			mPhase = phase;
			mCount++;
		}

		public void update(double rssi, double phase, double frequency) {
			mRssi = rssi;
			mPhase = phase;
			mFrequency = frequency;
			mCount++;
		}

		@Override
		public String toString() {
			if (mDataType == DATA_TYPE_RFID)
				return String.format(Locale.US, "[%s], %.2f, %.2f", mData, mRssi, mPhase);
			else 
				return String.format(Locale.US, "[%s], [%s], [%s]", mData, mBarcodeType, mBarcodeId);
		}
	}
}
