using Android.App;
using Android.OS;
using Android.Support.V7.App;
using Android.Runtime;
using Android.Widget;
using Android.Views;
using System.Collections.Generic;
using System.Threading;
using System;
using static Android.App.ActivityManager;
using Android.Content;
using Android.Content.PM;
using Android.Media;
using Android.Hardware;

namespace StanUrzadzenia
{
    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
    public class MainActivity : AppCompatActivity
    {
        ListView listView;

        class _Handler : Handler
        {
            private MainActivity activity;

            public _Handler(MainActivity activity)
            {
                this.activity = activity;
            }

            public override void HandleMessage(Message message)
            {
                activity.odswiezListe();
            }
        };

        _Handler handler;        

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            TextView naglowek = FindViewById<TextView>(Resource.Id.naglowek);
            naglowek.Text += "\n" + Build.Manufacturer + " " + Build.Model + " (" + Build.Product + ")";

            listView = FindViewById<ListView>(Resource.Id.listView);
            odswiezListe();

            const int coIleMilisekundOswiezacListe = 2000; //2s
            handler = new _Handler(this);
            ThreadStart ts = new ThreadStart( //wątek .NET, alternatywnie Java.Lang.Thread
                () =>
                {
                    while (true)
                    {
                        //w osobnym watku
                        handler.SendEmptyMessage(0);
                        try
                        {
                            Thread.Sleep(coIleMilisekundOswiezacListe);
                        }
                        catch //(ThreadInterruptedException exc)
                        {
                        }
                    }
                });
            Thread timer = new Thread(ts);
            timer.Start();
        }

        class BatteryReveiver : BroadcastReceiver
        {
            public override void OnReceive(Context context, Intent intent)
            {
                int bateriaPoziom = intent.GetIntExtra(BatteryManager.ExtraLevel, -1);
                if (bateriaPoziom < 10) Toast.MakeText(context, "Niski stan baterii", ToastLength.Long).Show();
                //odswiezListe();
            }
        }

        BroadcastReceiver batteryReceiver;

        private void odswiezListe()
        {
            int pozycja = listView.FirstVisiblePosition;
            View v = listView.GetChildAt(0);
            int top = (v == null) ? 0 : v.Top;

            List<UrządzenieInfo> listaUrządzeń = new List<UrządzenieInfo>();
            listaUrządzeń.Add(odczytajWersjęSystemu(this));
            listaUrządzeń.Add(odczytajStanPamięci(this));
            listaUrządzeń.Add(odczytajStanGłównejKartyPamięci(this));
            listaUrządzeń.Add(odczytajStanDodatkowejKartyPamięci(this));
            listaUrządzeń.Add(odczytajStanProcesora(this));

            batteryReceiver = new BatteryReveiver();
            IntentFilter intentFilter = new IntentFilter(Intent.ActionBatteryChanged);
            Intent intent = this.ApplicationContext.RegisterReceiver(batteryReceiver, intentFilter);
            listaUrządzeń.Add(odczytajStanBaterii(this, intent));

            listaUrządzeń.Add(odczytajObecnoscDodatkowychUrzadzen(this));
            listaUrządzeń.Add(odczytajStanAudio(this));
            listaUrządzeń.Add(odczytajObecnoscCzujnikow(this));

            //tu dodawać opisy stanu kolejnych urzadzen

            UrzadzeniaAdapter a = new UrzadzeniaAdapter(this, Resource.Layout.wiersz, listaUrządzeń);
            listView.Adapter = a;

            listView.SetSelectionFromTop(pozycja, top);
        }

        protected override void OnResume()
        {
            base.OnResume();
            Toast.MakeText(this, "Rozpoczynam odczyty czujników", ToastLength.Long).Show();
        }

        protected override void OnPause()
        {
            base.OnPause();
            if (batteryReceiver != null) this.ApplicationContext.UnregisterReceiver(batteryReceiver);
        }

        #region Metody odczytujące stan urządzenia
        private static UrządzenieInfo odczytajWersjęSystemu(Activity activity)
        {
            UrządzenieInfo systemInfo = new UrządzenieInfo();
            systemInfo.nazwa = "Wersja systemu";
            systemInfo.typInformacji = TypInformacji.Inne;
            systemInfo.polozeniePaska = -1;
            systemInfo.opis = "\nBieżąca data i czas: " + DateTime.Now.ToString();
            systemInfo.opis += "\nBieżąca data: " + DateTime.Now.ToLongTimeString();
            systemInfo.opis += "\nBieżący czas: " + DateTime.Now.ToLongDateString();
            systemInfo.opis += "\nProducent: " + Build.Manufacturer;
            systemInfo.opis += "\nUrządzenia: " + Build.Device;
            systemInfo.opis += "\nWersja: " + Build.VERSION.Release + " (" + Build.VERSION.Incremental + ")";
            systemInfo.opis += "\nTyp CPU: " + Build.CpuAbi; //deprecated
            systemInfo.opis += "\nTyp CPU: ";
            foreach(string abi in Build.SupportedAbis) //API 21
            {
                systemInfo.opis += "\n\t" + abi;
            }
            systemInfo.opis += "\nWyświetlacz: " + Build.Display;
            return systemInfo;
        }

        private static UrządzenieInfo odczytajStanPamięci(Activity activity)
        {
            //Pamięć wewnętrzna
            UrządzenieInfo pi = new UrządzenieInfo();
            pi.typInformacji = TypInformacji.StanUrzadzenia;
            pi.nazwa = "Pamięć (RAM)";

            ActivityManager am = (ActivityManager)activity.GetSystemService(ActivityService);
            MemoryInfo mi = new MemoryInfo();
            am.GetMemoryInfo(mi);
            long pamięćDostępną = mi.AvailMem / 1024; //kB
                                                      //mi.totalMem
            long pamięćCałkowita = LinuxHelper.ReadRAMTotalSizeKB();
            long pamięćZajęta = pamięćCałkowita - pamięćDostępną;
            pi.opis = "Dostępna pamięć: " + pamięćDostępną + "/" + pamięćCałkowita;
            pi.polozeniePaska = (int)(pamięćZajęta * 100 / pamięćCałkowita);
            return pi;
        }

        private static Tuple<string, int> pobierzStanPamięci(Java.IO.File memoryDirectory)
        {
            StatFs systemPlików = new StatFs(memoryDirectory.Path);
            long wolneMiejsce =
                    systemPlików.AvailableBlocksLong *
                            systemPlików.BlockSizeLong
                            / 1024 / 1024; //MB
            long rozmiar =
                    systemPlików.BlockCountLong *
                            systemPlików.BlockSizeLong
                            / 1024 / 1024; //MB
            long zajęteMiejsce = rozmiar - wolneMiejsce;

            String opis = "Ścieżka: " + memoryDirectory.Path + "\n";
            opis += "Wolne miejsce: " + wolneMiejsce + " / " + rozmiar;
            int procent = (int)(zajęteMiejsce * 100 / rozmiar);

            Tuple<string, int> tuple = new Tuple<string, int>(opis, procent);
            return tuple;
        }

        private static UrządzenieInfo odczytajStanGłównejKartyPamięci(Activity activity)
        {
            Tuple<string, int> tuple = pobierzStanPamięci(Android.OS.Environment.RootDirectory);

            UrządzenieInfo kartaPamięciInfo = new UrządzenieInfo();
            kartaPamięciInfo.typInformacji = TypInformacji.StanUrzadzenia;
            kartaPamięciInfo.nazwa = "Głowna karta pamięci";
            kartaPamięciInfo.opis = tuple.Item1;
            kartaPamięciInfo.polozeniePaska = tuple.Item2;
            return kartaPamięciInfo;
        }

        private static UrządzenieInfo odczytajStanDodatkowejKartyPamięci(Activity activity)
        {
            UrządzenieInfo kartaPamięciInfo = new UrządzenieInfo();
            kartaPamięciInfo.typInformacji = TypInformacji.StanUrzadzenia;
            kartaPamięciInfo.nazwa = "Dodatkowa karta pamięci";

            if (Android.OS.Environment.ExternalStorageState.Equals(Android.OS.Environment.MediaMounted))
            {
                Tuple<string, int> tuple = pobierzStanPamięci(Android.OS.Environment.ExternalStorageDirectory);
                kartaPamięciInfo.opis = tuple.Item1;
                kartaPamięciInfo.polozeniePaska = tuple.Item2;
            }
            else
            {
                kartaPamięciInfo.opis = "Brak";
                kartaPamięciInfo.polozeniePaska = -1;
            }
            return kartaPamięciInfo;
        }

        private static UrządzenieInfo odczytajStanProcesora(Activity activity)
        {
            UrządzenieInfo procesorInfo = new UrządzenieInfo();
            procesorInfo.typInformacji = TypInformacji.StanUrzadzenia;
            procesorInfo.nazwa = "Procesor (CPU)";
            int procesorObciąrzenie = (int)Math.Round(100 * LinuxHelper.ReadCPUUsage());
            String opisProcesora = LinuxHelper.ReadCPUInfo();
            procesorInfo.opis = opisProcesora + "\n";
            procesorInfo.opis += "Obciążenie procesora: " + procesorObciąrzenie + "%";
            procesorInfo.polozeniePaska = procesorObciąrzenie;
            return procesorInfo;
        }

        static private UrządzenieInfo odczytajStanBaterii(Activity activity, Intent intent)
        {
            //Bateria (API 5)            	
            UrządzenieInfo bateriaInfo = new UrządzenieInfo();
            bateriaInfo.typInformacji = TypInformacji.StanUrzadzenia;
            bateriaInfo.nazwa = "Bateria";
            if (intent.GetBooleanExtra(BatteryManager.ExtraPresent, false))
            {
                String bateriaTechnologia = intent.GetStringExtra(BatteryManager.ExtraTechnology);
                BatteryStatus bateriaStan = (BatteryStatus)intent.GetIntExtra(BatteryManager.ExtraStatus, -1);
                String bateriaStanOpis = "";
                switch (bateriaStan)
                {
                    case BatteryStatus.Charging:                    
                        bateriaStanOpis = "ładowanie";
                        break;
                    case BatteryStatus.Discharging:
                        bateriaStanOpis = "rozładowywanie";
                        break;
                    case BatteryStatus.Full:
                        bateriaStanOpis = "w pełni naładowana";
                        break;
                    case BatteryStatus.NotCharging:
                        bateriaStanOpis = "nie ładowana";
                        break;
                    default:
                    case BatteryStatus.Unknown:
                        bateriaStanOpis = "nieznany";
                        break;
                }
                BatteryPlugged bateriaMetodaLadowania = (BatteryPlugged)intent.GetIntExtra(BatteryManager.ExtraPlugged, -1);
                String bateriaMetodaLadowaniaOpis = "";
                switch (bateriaMetodaLadowania)
                {
                    case BatteryPlugged.Ac:
                        bateriaMetodaLadowaniaOpis = "AC";
                        break;
                    case BatteryPlugged.Usb:
                        bateriaMetodaLadowaniaOpis = "USB";
                        break;
                    case BatteryPlugged.Wireless:
                        bateriaMetodaLadowaniaOpis = "wireless";
                        break;
                    default:
                        bateriaMetodaLadowaniaOpis = "-";
                        break;
                }
                int bateriaSkala = intent.GetIntExtra(BatteryManager.ExtraScale, -1);
                int bateriaPoziom = intent.GetIntExtra(BatteryManager.ExtraLevel, -1);
                int bateriaNapiecie = intent.GetIntExtra(BatteryManager.ExtraVoltage, -1);
                int bateriaTemperatura = intent.GetIntExtra(BatteryManager.ExtraTemperature, -1);
                bateriaInfo.opis = "Technologia: " + bateriaTechnologia + ", stan: " + bateriaStanOpis + " (" + bateriaMetodaLadowaniaOpis + "), poziom naładowania baterii: " + bateriaPoziom + "/" + bateriaSkala + ", napięcie: " + bateriaNapiecie / 1000 + " V, temperatura: " + bateriaTemperatura / 10 + " °C";
                bateriaInfo.polozeniePaska = bateriaPoziom * 100 / bateriaSkala;
            }
            else
            {
                bateriaInfo.opis = "Brak";
                bateriaInfo.polozeniePaska = -1;
            }
            return bateriaInfo;
        }

        static private UrządzenieInfo odczytajObecnoscDodatkowychUrzadzen(Activity activity)
        {
            //Dodatkowe urządzenia
            UrządzenieInfo dodatkoweInfo = new UrządzenieInfo();
            dodatkoweInfo.typInformacji = TypInformacji.Inne;
            dodatkoweInfo.nazwa = "Dodatkowe urządzenia";
            dodatkoweInfo.polozeniePaska = -1;

            PackageManager pm = activity.PackageManager;
            bool czyTelefonObecny = pm.HasSystemFeature(PackageManager.FeatureTelephony);
            dodatkoweInfo.opis = "Telefon: " + (czyTelefonObecny ? "obecny" : "brak");
            if (czyTelefonObecny)
            {
                dodatkoweInfo.opis = pm.HasSystemFeature(PackageManager.FeatureTelephonyGsm) ? " (GSM)" : "";
                dodatkoweInfo.opis = pm.HasSystemFeature(PackageManager.FeatureTelephonyCdma) ? " (CDMA)" : "";
            }
            bool czyKameraObecna = pm.HasSystemFeature(PackageManager.FeatureCamera);
            dodatkoweInfo.opis += "\nAparat fotograficzny/kamera: " + (czyKameraObecna ? "obecna" : "brak");
            if (czyKameraObecna)
            {
                dodatkoweInfo.opis += "\n\tautomatyczna regulacja ostrości: " + (pm.HasSystemFeature(PackageManager.FeatureCameraAutofocus) ? "obecna" : "brak");
                dodatkoweInfo.opis += "\n\tlampa błyskowa: " + (pm.HasSystemFeature(PackageManager.FeatureCameraFlash) ? "obecna" : "brak");
            }
            dodatkoweInfo.opis += "\nCzujnik światła: " + (pm.HasSystemFeature(PackageManager.FeatureSensorLight) ? "obecny" : "brak");
            dodatkoweInfo.opis += "\nCzujnik zbliżeniowy: " + (pm.HasSystemFeature(PackageManager.FeatureSensorProximity) ? "obecny" : "brak");
            dodatkoweInfo.opis += "\nEkran wielodotykowy: " + (pm.HasSystemFeature(PackageManager.FeatureTouchscreenMultitouch) ? "obecny" : "brak");
            dodatkoweInfo.opis += "\nAnimowana tapeta: " + (pm.HasSystemFeature(PackageManager.FeatureLiveWallpaper) ? "obecna" : "brak");

            return dodatkoweInfo;
        }

        static private UrządzenieInfo odczytajStanAudio(Activity activity)
        {
            //Stan audio
            UrządzenieInfo audioInfo = new UrządzenieInfo();
            audioInfo.typInformacji = TypInformacji.Inne;
            audioInfo.nazwa = "Audio";
            audioInfo.polozeniePaska = -1;

            AudioManager am = (AudioManager)activity.GetSystemService(Context.AudioService);
            Mode trybAudio = am.Mode;
            String trybAudioOpis = "Tryb audio: ";
            switch (trybAudio)
            {
                case Mode.Normal:
                    trybAudioOpis += "normalny";
                    break;
                case Mode.Ringtone:
                    trybAudioOpis += "dzwonki";
                    break;
                case Mode.InCall:
                    trybAudioOpis += "w trakcie rozmowy (telefon)";
                    break;
                case Mode.InCommunication:
                    trybAudioOpis += "w trakcie rozmowy (VoIP)";
                    break;
                default:
                case Mode.Invalid:                
                    trybAudioOpis += "niezanany lub niepoprawny";
                    break;
            }
            audioInfo.opis = trybAudioOpis;

            RingerMode trybDzwonka = am.RingerMode;
            String trybDzwonkaOpis = "Rodzaj dzwonka: ";
            switch (trybDzwonka)
            {
                case RingerMode.Normal:
                    trybDzwonkaOpis += "normalny";
                    break;
                case RingerMode.Silent:
                    trybDzwonkaOpis += "wyciszony";
                    break;
                case RingerMode.Vibrate:
                    trybDzwonkaOpis += "wibracje";
                    break;
                default:
                    trybDzwonkaOpis += "niezanany";
                    break;
            }
            audioInfo.opis += "\n" + trybDzwonkaOpis;

            audioInfo.opis += "\nWyciszenie mikrofonu: " + (am.MicrophoneMute ? "tak" : "nie");
            audioInfo.opis += "\nOdtwarzanie muzyki: " + (am.IsMusicActive ? "tak" : "nie");

            audioInfo.opis += "\nGłośność systemu: " + am.GetStreamVolume(Stream.System) + "/" + am.GetStreamMaxVolume(Stream.System);
            audioInfo.opis += "\nGłośność dzwonka: " + am.GetStreamVolume(Stream.Ring) +"/" + am.GetStreamMaxVolume(Stream.Ring);
            audioInfo.opis += "\nGłośność alarmu: " + am.GetStreamVolume(Stream.Alarm) + "/" + am.GetStreamMaxVolume(Stream.Alarm);
            audioInfo.opis += "\nGłośność rozmowy: " + am.GetStreamVolume(Stream.VoiceCall) + "/" + am.GetStreamMaxVolume(Stream.VoiceCall);
            audioInfo.opis += "\nGłośność powiadomień: " + am.GetStreamVolume(Stream.Notification) + "/" + am.GetStreamMaxVolume(Stream.Notification);
            audioInfo.polozeniePaska = 100 * am.GetStreamVolume(Stream.System) / am.GetStreamMaxVolume(Stream.System);

            return audioInfo;
        }

        static private String opisCzujnika(IList<Sensor> lista, string nazwa)
        {
            string opis = nazwa + ": ";
            if (lista.Count > 1) opis += "\n";
            if (lista.Count > 0)
                for (int i = 0; i < lista.Count; ++i)
                {
                    if (lista.Count > 1) opis += "\t";
                    Sensor czujnik = lista[i];
                    opis += czujnik.Name + ", wersja: " + czujnik.Version + "\n";
                }
            else opis += "brak\n";
            return opis;
        }

        static private UrządzenieInfo odczytajObecnoscCzujnikow(Activity activity)
        {
            //Dodatkowe urządzenia
            UrządzenieInfo czujnikiInfo = new UrządzenieInfo();
            czujnikiInfo.typInformacji = TypInformacji.Inne;
            czujnikiInfo.nazwa = "Czujniki";
            czujnikiInfo.polozeniePaska = -1;

            SensorManager sm = (SensorManager)activity.GetSystemService(Context.SensorService);
            czujnikiInfo.opis = opisCzujnika(sm.GetSensorList(SensorType.Accelerometer), "Akcelerator");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Gyroscope), "Żyroskop");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Light), "Światło");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.MagneticField), "Pole magnetyczne");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Orientation), "Orientacja");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Pressure), "Ciśnienie");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Proximity), "Odległość");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.Temperature), "Temperatura");
            czujnikiInfo.opis += opisCzujnika(sm.GetSensorList(SensorType.AmbientTemperature), "Temperatura otoczenia");

            return czujnikiInfo;
        }
        #endregion
    }
}