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;

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();
        }

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

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

            //tu dodawać opisy stanu kolejnych urzadzen

            UrzadzeniaAdapter a = new UrzadzeniaAdapter(this, Resource.Layout.wiersz, listaUrzadzeń);
            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();
        }

        #region Metody odczytujące stan urządzenia
        static private 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 += "\nS/N: " + Build.Serial;
            systemInfo.opis += "\nWersja: " + Build.VERSION.Release + " (" + Build.VERSION.Incremental + ")";
            systemInfo.opis += "\nPoziom API: " + Build.VERSION.SdkInt;
            //systemInfo.opis += "\nTyp CPU: " + Build.CpuAbi; //deprecated
            systemInfo.opis += "\nTypy CPU: ";
            foreach(string abi in Build.SupportedAbis) //API 21
            {
                systemInfo.opis += "\n\t" + abi;
            }
            systemInfo.opis += "\nWyświetlacz: " + Build.Display;
            return systemInfo;
        }

        static private 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ępna = mi.AvailMem / 1024; //kB
                                                      //mi.totalMem
            long pamięćCałkowita = LinuxHelper.ReadRAMTotalSizeKB();
            long pamięćZajęta = pamięćCałkowita - pamięćDostępna;
            pi.opis = "Dostępna pamięć: " + pamięćDostępna + "/" + pamięćCałkowita;
            pi.polozeniePaska = (int)(pamięćZajęta * 100 / pamięćCałkowita);
            return pi;
        }

        static private 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;
        }

        static private 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;
        }

        static private 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;
        }

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