package devices.RTC_I2C;

import java.text.ParseException;

import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.keywords.DateTime;
import jGPIO.mycodes;

@BA.ShortName("RTC_Data")
public class RTC_Data {
	public int second;
	public int minute;
	public int hour;
	public int date;
	public int month;
	public int year;
	public int DayOfWeek;
	
	private boolean correctdata = false;
	private RTC_Data_Event javaevent;
	
	@BA.Hide
	public void SetJavaEvent(RTC_Data_Event event) {
		javaevent = event;
	}
	
	private void raise_log(String msg) {
		if (javaevent!=null)
		{
			javaevent.Log(msg);
		}
	}
	
	/**
	 * Initialize RTC_Data values based on current System Clock 
	 */
	public void Initialize_from_Now() {
		StringBuilder str = new StringBuilder();
		str.append("RTC_Data Initialize_from_Now :").append(System.lineSeparator());
		long value = DateTime.getNow();
		str.append("Now value = ").append(value).append(System.lineSeparator());
		second = DateTime.GetSecond(value);
		str.append("second=").append(second).append(", ");
		minute = DateTime.GetMinute(value);
		str.append("minute=").append(minute).append(", ");
		hour = DateTime.GetHour(value);
		str.append("hour=").append(hour).append(", ");
		date = DateTime.GetDayOfMonth(value);
		str.append("date=").append(date).append(", ");
		month = DateTime.GetMonth(value);
		str.append("month=").append(month).append(", ");
		year = DateTime.GetYear(value);
		str.append("year=").append(year).append(", ");
		DayOfWeek = DateTime.GetDayOfWeek(value);
		str.append("Day Of Week=").append(DayOfWeek).append(", ");
		correctdata = true;
		raise_log(str.toString());
		System.out.println(str.toString());
	}
	
	/**
	 * Get RTC_Data value in DateTime tick
	 * @return 0 if invalid
	 */
	public long GetDateTimeTick() {
		if (correctdata) {
			
			String dateformat = DateTime.getDateFormat();
			String timeformat = DateTime.getTimeFormat();
			boolean need_change_date = false;
			boolean need_change_time = false;
			
			if (dateformat!="MM/dd/yyyy") {
				DateTime.setDateFormat("MM/dd/yyyy");		// set default date format
				need_change_date = true;
				
			}
			if (timeformat!="HH:mm:ss") {
				DateTime.setTimeFormat("HH:mm:ss");			// set default time format
				need_change_time = true;
				
			}
			
			long result;
			try {
				result = DateTime.DateTimeParse(getDate_in_String(), getTime_in_String());
			} catch (ParseException e) {
				result = 0;
				raise_log("GetDateTimeTick ParseException, Msg:"+e.getMessage()+", Caused:"+e.getCause());
			}
			
			if (need_change_date) DateTime.setDateFormat(dateformat);
			if (need_change_time) DateTime.setTimeFormat(timeformat);
			
			return result;
		}
		raise_log("GetDateTimeTick doesn't contain valid data");
		return 0;
	}
	
	
	public void Initialize_from_DS1307(byte[] bb) {
		StringBuilder str = new StringBuilder();
		str.append("RTC_Data Initialize_from_DS1307 : ").append(System.lineSeparator());
		
		correctdata = false;
		if (bb==null) {
			str.append("Failed, RTC bytes is null");
			raise_log(str.toString());
			return;
		}
		if (bb.length<7) {
			str.append("Failed, RTC bytes must 7 bytes, current = "+bb.length+" bytes");
			raise_log(str.toString());
			return;
		}
		
		str.append("RTC raw bytes : ").append(mycodes.printbytes(bb)).append(System.lineSeparator());
		
		second = ((bb[0] & 0x70)>>4)*10 + (bb[0] & 0x0F);
		if ((second<0) || (second>59)) {
			str.append(" Failed, contain invalid second=").append(second);
			raise_log(str.toString());
			return;
		} else {
			str.append("second=").append(second).append(", ");
		}
		
		minute = ((bb[1] & 0x70)>>4)*10 + (bb[1] & 0x0F);
		if ((minute<0)||(minute>59)) {
			str.append(" Failed, contain invalid minute=").append(minute);
			raise_log(str.toString());
			return;
		} else {
			str.append("minute=").append(minute).append(", ");
		}
		
		//detect AM/PM
		if ((bb[2] & 0x40)==0) {
			// 24H
			hour = ((bb[2] & 0x30)>>4)*10 + (bb[2] & 0x0F);
			str.append("hour24=").append(hour);
		} else {
			// 12H, ada AM/PM
			if ((bb[2] & 0x20)==0){
				// AM
				hour = ((bb[2] & 0x10)>>4)*10 + (bb[2] & 0x0F);
				str.append("hourAM=").append(hour);
				if (hour==12) hour = 0;		// 12AM = jam 00
			} else {
				// PM
				hour = ((bb[2] & 0x10)>>4)*10 + (bb[2] & 0x0F);
				str.append("hourPM=").append(hour);
				if (hour!=12) hour+=12;		// 1PM = jam 13, tapi jam 12PM ya jam 12
			}
			
		}
		if ((hour<0)|| (hour>23)) {
			str.append(" Failed, contain invalid hour=").append(hour);
			raise_log(str.toString());
			return;
		} else {
			str.append(" hour=").append(hour).append(", ");
		}
		
		DayOfWeek = bb[3] & 0x7;
		if ((DayOfWeek<1) || (DayOfWeek>7)) {
			str.append(" Failed, contain invalid DayOfWeek=").append(DayOfWeek);
			raise_log(str.toString());
			return;
		} else {
			str.append("DayOfWeek=").append(DayOfWeek).append(", ");
		}
		
		date = ((bb[4] & 0x30)>>4) * 10 + (bb[4] & 0x0F);
		if ((date<1) || (date>31)) {
			str.append(" Failed, contain invalid Date=").append(date);
			raise_log(str.toString());
			return;
		} else {
			str.append(" Date=").append(date).append(", ");
		}
		
		month = ((bb[5] & 0x10)>>4) * 10 + (bb[5] & 0x0F);
		if ((month<1)||(month>12)) {
			str.append(" Failed, contain invalid Month=").append(month);
			raise_log(str.toString());
			return;
		} else {
			str.append(" Month=").append(month).append(", ");
		}
		
		year = ((bb[6] & 0xF0)>>4) * 10 + (bb[6] & 0x0F);
		if ((year<0)||(year>99)) {
			str.append(" Failed, contain invalid year=").append(year);
			raise_log(str.toString());
			return;
		} else {
			str.append(" Year=").append(year).append(System.lineSeparator());
		}
		year+=2000;
		correctdata = true;
		raise_log(str.toString());
	}
	
	@BA.Hide
	/**
	 * Get RTC_Data values in DS1307 data bytes 
	 * @return  1 byte Address(00h) + 7 bytes data
	 */
	public byte[] Get_DS1307_bytes() {
		byte[] result = new byte[7+1];		// 7 bytes data + 1 address;
		result[0] = 0;		// address
		
		// temporary value
		int XH, XL;
		
		// second
		XH = second / 10;
		XL = second % 10;
		result[1] = (byte)(((XH << 4) | XL) & 0x7F);	// Clock Halt(bit 7) =0, start oscillator
		
		// minute
		XH = minute / 10;
		XL = minute % 10;
		result[2] = (byte)((XH << 4) | XL);
		
		// hour
		XH = hour / 10;
		XL = hour % 10;
		result[3] = (byte)(((XH << 4) | XL) & 0x3F);	// 24H mode (bit 6 = 0)
		
		// Day of Week
		result[4] = (byte)(DayOfWeek);
		
		// Date
		XH = date / 10;
		XL = date % 10;
		result[5] = (byte)((XH <<4) | XL);
		
		// month
		XH = month / 10;
		XL = month % 10;
		result[6] = (byte)((XH << 4) | XL);
		
		// year
		int yy = year - 2000;
		XH = yy / 10;
		XL = yy % 10;
		result[7] = (byte)((XH <<4) | XL);
		
		return result;
	}
	
	
	/**
	 * Initialize RTC_Data based on DS3231 reading
	 * Check for IsCorrectData() for examining correct values 
	 * @param bb : 7 bytes of DS3231 data
	 */
	public void Initialize_from_DS3231(byte[] bb) {
		StringBuilder str = new StringBuilder();
		str.append("RTC_Data Initialize_from_DS3231 : ").append(System.lineSeparator());
		
		correctdata = false;
		if (bb==null) {
			str.append("Failed, RTC bytes is null");
			raise_log(str.toString());
			return;
		}
		if (bb.length<7) {
			str.append("Failed, RTC bytes must 7 bytes, current = "+bb.length+" bytes");
			raise_log(str.toString());
			return;
		}
		
		str.append("RTC raw bytes : ").append(mycodes.printbytes(bb)).append(System.lineSeparator());
		
		second = ((bb[0] & 0x70)>>4)*10 + (bb[0] & 0x0F);
		if ((second<0) || (second>59)) {
			str.append(" Failed, contain invalid second=").append(second);
			raise_log(str.toString());
			return;
		} else {
			str.append("second=").append(second).append(", ");
		}
		
		minute = ((bb[1] & 0x70)>>4)*10 + (bb[1] & 0x0F);
		if ((minute<0)||(minute>59)) {
			str.append(" Failed, contain invalid minute=").append(minute);
			raise_log(str.toString());
			return;
		} else {
			str.append("minute=").append(minute).append(", ");
		}
		
		//detect AM/PM
		if ((bb[2] & 0x40)==0) {
			// 24H
			hour = ((bb[2] & 0x30)>>4)*10 + (bb[2] & 0x0F);
			str.append("hour24=").append(hour);
		} else {
			// 12H, ada AM/PM
			if ((bb[2] & 0x20)==0){
				// AM
				hour = ((bb[2] & 0x10)>>4)*10 + (bb[2] & 0x0F);
				str.append("hourAM=").append(hour);
				if (hour==12) hour = 0;		// 12AM = jam 00
			} else {
				// PM
				hour = ((bb[2] & 0x10)>>4)*10 + (bb[2] & 0x0F);
				str.append("hourPM=").append(hour);
				if (hour!=12) hour+=12;		// 1PM = jam 13, tapi jam 12PM ya jam 12
			}
			
		}
		if ((hour<0)|| (hour>23)) {
			str.append(" Failed, contain invalid hour=").append(hour);
			raise_log(str.toString());
			return;
		} else {
			str.append(" hour=").append(hour).append(", ");
		}
		
		
		DayOfWeek = bb[3] & 0x7;
		if ((DayOfWeek<1) || (DayOfWeek>7)) {
			str.append(" Failed, contain invalid DayOfWeek=").append(DayOfWeek);
			raise_log(str.toString());
			return;
		} else {
			str.append("DayOfWeek=").append(DayOfWeek).append(", ");
		}
		
		date = ((bb[4] & 0x30)>>4) * 10 + (bb[4] & 0x0F);
		if ((date<1) || (date>31)) {
			str.append(" Failed, contain invalid Date=").append(date);
			raise_log(str.toString());
			return;
		} else {
			str.append(" Date=").append(date).append(", ");
		}
		
		month = ((bb[5] & 0x10)>>4) * 10 + (bb[5] & 0x0F);
		if ((month<1)||(month>12)) {
			str.append(" Failed, contain invalid Month=").append(month);
			raise_log(str.toString());
			return;
		} else {
			str.append(" Month=").append(month).append(", ");
		}
		
		year = ((bb[6] & 0xF0)>>4) * 10 + (bb[6] & 0x0F);
		if ((year<0)||(year>99)) {
			str.append(" Failed, contain invalid year=").append(year);
			raise_log(str.toString());
			return;
		} else {
			str.append(" Year=").append(year).append(System.lineSeparator());
		}
		year+=2000;
		correctdata = true;
		raise_log(str.toString());
	}
	
	@BA.Hide
	/**
	 * Get RTC_Data values in DS3231 data bytes 
	 * @return  1 byte Address(00h) + 7 bytes data
	 */
	public byte[] Get_DS3231_bytes() {
		byte[] result = new byte[7+1];		// 7 bytes data + 1 address;
		result[0] = 0;		// address
		
		// temporary value
		int XH, XL;
		
		// second
		XH = second / 10;
		XL = second % 10;
		result[1] = (byte)((XH << 4) | XL);
		
		// minute
		XH = minute / 10;
		XL = minute % 10;
		result[2] = (byte)((XH << 4) | XL);
		
		// hour
		XH = hour / 10;
		XL = hour % 10;
		result[3] = (byte)((XH << 4) | XL);
		
		// Day of Week
		result[4] = (byte)(DayOfWeek);
		
		// Date
		XH = date / 10;
		XL = date % 10;
		result[5] = (byte)((XH <<4) | XL);
		
		// month
		XH = month / 10;
		XL = month % 10;
		result[6] = (byte)((XH << 4) | XL);
		
		// year
		int yy = year - 2000;
		XH = yy / 10;
		XL = yy % 10;
		result[7] = (byte)((XH <<4) | XL);
		
		return result;
	}
	
	/**
	 * Get RTC_Data Date in String
	 * @return in format MM/dd/yyyy
	 */
	public String getDate_in_String() {
		if (correctdata) {
			StringBuilder datetext = new StringBuilder();
			if (month<10) datetext.append("0");
			datetext.append(month).append("/");
			if (date<10) datetext.append("0");
			datetext.append(date).append("/");
			datetext.append(year);
			return datetext.toString();
		}
		return "";
	}
	
	/**
	 * Get RTC_Data Time in String
	 * @return in format HH:mm:ss
	 */
	public String getTime_in_String() {
		if (correctdata) {
			StringBuilder timetext = new StringBuilder();
			if (hour<10) timetext.append("0");
			timetext.append(hour).append(":");
			if (minute<10) timetext.append("0");
			timetext.append(minute).append(":");
			if (second<10) timetext.append("0");
			timetext.append(second);
			return timetext.toString();	
		}
		return "";
	}
	
	/**
	 * Get RTC_Data Date and Time in String
	 */
	public String toString() {
		if (correctdata) {
			return getDate_in_String()+" "+getTime_in_String();
		}
		return "";
	}
	
	/**
	 * Check if Initialization success
	 * @return true if correct data found
	 */
	public boolean IsCorrectData() {
		return correctdata;
	}
}
