using System;
using System.Collections.Generic;
using System.Collections;
using MiMic.CsApi;

namespace MiMic.CsApi.LPC1769
{
	public class Port:MiMicClass
	{

		private class REG
		{
			public static UInt32?[] _PINSEL={0x4002C000,0x4002C004,0x4002C008,0x4002C00C,0x4002C010,null,null,0x4002C0C0,null,0x4002C024,0x4002C028};
			public static UInt32?[] _PINMODE={0x4002C040,0x4002C044,0x4002C048,0x4002C04C,0x4002C050,0x4002C054,0x4002C058,0x4002C05C,null,0x4002C064};
			public static UInt32?[] _PINMODE_OD={0x4002C068,0x4002C06C,0x4002C070,0x4002C074,0x4002C078};
		}
		internal Mcu _ref_mcu;
		protected LPC1769.PinRegInfo[] _pininfo;
		public Port (Mcu i_mcu,PinId[] i_pins,Pin.Option[] i_opts)
		{
			this._ref_mcu=i_mcu;
			this._pininfo=new LPC1769.PinRegInfo[i_pins.Length];
			//ピン情報に変換
			for(int i=0;i<i_pins.Length;i++){
				this._pininfo[i]=LPC1769.getPinRegInfo(i_pins[i]);
			}
			if(i_opts!=null){
				this.setOpts(i_opts);
			}
		}
		
		internal string BCF_setOpts(Pin.Option[] i_opts,List<UInt32> i_db)
		{
			//10/5レジスタ分のワーク領域を作る。
			UInt32[] selr={0,0,0,0,0,0,0,0,0,0};
			UInt32[] selr_mask={0,0,0,0,0,0,0,0,0,0};
			UInt32[] modr={0,0,0,0,0,0,0,0,0,0};
			UInt32[] modr_mask={0,0,0,0,0,0,0,0,0,0};
			UInt32[] odr={0,0,0,0,0};
			UInt32[] odr_mask={0,0,0,0,0};
				
			//pinsとoptsの数は同じだよね？
			if(this._pininfo.Length!=i_opts.Length){
				throw new MiMicException();
			}
			
			//レジスタ値、マスクの生成
			for(int i=0;i<i_opts.Length;i++)
			{
				//Exception will be thrown when casting failed.
				LPC1769.PinRegInfo pi=this._pininfo[i];
				Pin.Option opt=i_opts[i];
				if(opt.sel!=null)
				{
					int idx=(int)pi.s;
					selr[idx]|=(((UInt32)opt.sel)<<((int)pi.smb));
					selr_mask[idx]|=((UInt32)0x3<<((int)pi.smb));
				}
				if(opt.mode!=null)
				{
					int idx=(int)pi.m;
					modr[idx]|=(((UInt32)opt.mode)<<(int)pi.smb);
					modr_mask[idx]|=((UInt32)0x3<<(int)pi.smb);
				}
				if(opt.od!=null)
				{
					int idx=(int)pi.o;
					odr[idx]|=(((UInt32)opt.od)<<(int)pi.ob);
					odr_mask[idx]|=((UInt32)0x1<<(int)pi.ob);
				}
			}
			//BCFを生成
			string bc="";
			for(int i=0;i<10;i++){
				if(selr_mask[i]!=0x0){
					bc+=LPC1769._BCF.setBit((UInt32)REG._PINSEL[i],selr_mask[i],selr[i],0,i_db);
				}
				if(modr_mask[i]!=0x0){
					bc+=LPC1769._BCF.setBit((UInt32)REG._PINMODE[i],modr_mask[i],modr[i],0,i_db);
				}
			}
			for(int i=0;i<5;i++){
				if(odr_mask[i]!=0x0){
					bc+=LPC1769._BCF.setBit((UInt32)REG._PINMODE_OD[i],odr_mask[i],odr[i],0,i_db);
				}
			}
			return bc;
		}
		public void setOpts(Pin.Option[] i_opts)
		{
			List<UInt32> db=new List<UInt32>();
			string bc=this.BCF_setOpts(i_opts,db);
			if(bc.Length==0){
				throw new MiMicException("i_opt is empty or invalid.");
			}
			//MiMicBCを生成して実行
			this._ref_mcu.callMiMicWithCheck(bc+LPCXpresso1769._BCF.END,db);
			return;
		}		
	}
}


