package com.manning.aip.dealdroid;

import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

import com.manning.aip.dealdroid.model.Item;
import com.manning.aip.dealdroid.model.Section;

import java.util.ArrayList;
import java.util.List;

public class DealList extends ListActivity {

   private static final int MENU_REPARSE = 0;

   private DealDroidApp app;
   private List<Item> items;  
   private DealsAdapter dealsAdapter;
   private ArrayAdapter<Section> spinnerAdapter;
   private Spinner sectionSpinner;
   private int currentSelectedSection;
   private ProgressDialog progressDialog;

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.deallist);
      
      progressDialog = new ProgressDialog(this);
      progressDialog.setCancelable(false);
      progressDialog.setMessage(getString(R.string.deal_list_retrieving_data));

      // Obiekt typu Application przechowuje stan całej aplikacji.
      app = (DealDroidApp) getApplication();

      // Tworzenie adaptera z początkowo pustą kolekcją elementów.
      items = new ArrayList<Item>();
      dealsAdapter = new DealsAdapter(items);
      
      // Adapter kontrolki ListView.
      setListAdapter(dealsAdapter);
      
      // Pobieranie listy kategorii z aplikacji (w razie potrzeby należy
      // też przetworzyć dane z kanału RSS).
      if (app.getSectionList().isEmpty()) {
         if (app.connectionPresent()) {
            new ParseFeedTask().execute();
         } else {
            Toast.makeText(this, getString(R.string.deal_list_network_unavailable), Toast.LENGTH_LONG).show();
         }
      } else {         
         resetListItems(app.getSectionList().get(0).getItems());
      }      

      // Kontrolka Spinner do wybierania kategorii.
      sectionSpinner = (Spinner) findViewById(R.id.section_spinner);
      spinnerAdapter =
               new ArrayAdapter<Section>(DealList.this, android.R.layout.simple_spinner_item, app.getSectionList());
      spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      sectionSpinner.setAdapter(spinnerAdapter);
      sectionSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
         @Override
         public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            if (currentSelectedSection != position) {
               currentSelectedSection = position;
               resetListItems(app.getSectionList().get(position).getItems());
            }
         }

         @Override
         public void onNothingSelected(AdapterView<?> parentView) {
            // Nic nie robi.
         }
      });      
   }
   
   private void resetListItems(List<Item> newItems) {
      items.clear();
      items.addAll(newItems);
      dealsAdapter.notifyDataSetChanged();
   }

   @Override
   protected void onListItemClick(ListView listView, View view, int position, long id) {
      view.setBackgroundColor(android.R.color.background_light);
      app.setCurrentItem(app.getSectionList().get(currentSelectedSection).getItems().get(position));
      Intent dealDetails = new Intent(DealList.this, DealDetails.class);
      startActivity(dealDetails);
   }

   @Override
   public void onPause() {
      if (progressDialog.isShowing()) {
         progressDialog.dismiss();
      }
      super.onPause();
   }
   
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      menu.add(0, DealList.MENU_REPARSE, 0, R.string.deal_list_reparse_menu);
      return true;
   }

   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      switch (item.getItemId()) {
         case MENU_REPARSE:
            if (app.connectionPresent()) {
               new ParseFeedTask().execute();               
            } else {
               Toast.makeText(this, getString(R.string.deal_list_network_unavailable), Toast.LENGTH_LONG).show();
            }
            return true;
      }
      return super.onOptionsItemSelected(item);
   }   

   // Używanie niestandardowego adaptera do kontrolowania układu i widoków.
   private class DealsAdapter extends ArrayAdapter<Item> {      

      public DealsAdapter(List<Item> items) {
         super(DealList.this, R.layout.list_item, items);
      }

      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
         
         if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.list_item, parent, false);
         }

         // Używanie klasy ViewHolder, aby zapobiec wielu wywołaniom 
         // metody findViewById (jeśli kolekcja jest duża).
         TextView text = (TextView) convertView.findViewById(R.id.deal_title);
         ImageView image = (ImageView) convertView.findViewById(R.id.deal_img);
         image.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ddicon));

         Item item = getItem(position);

         if (item != null) {
            text.setText(item.getTitle());
            Bitmap bitmap = app.getImageCache().get(item.getItemId());
            if (bitmap != null) {
               image.setImageBitmap(bitmap);
            } else {
               // Przypisywanie do rysunku identyfikatora jako tagu używanego w zadaniu.               
               image.setTag(item.getItemId());
               // Do pobierania każdego rysunku używany jest odrębny wątek.
               // W tej wersji rozwiązanie może prowadzić do problemów.
               // Należałoby zatrzymać wszystkie wątki w metodzie onPause.               
               new RetrieveImageTask(image).execute(item.getSmallPicUrl());
            }
         }

         return convertView;
      }
   }
   
   // Używanie klasy AsyncTask<Params, Progress, Result>, aby wygodnie 
   // wykonywać zadania poza wątkiem interfejsu użytkownika.
   private class ParseFeedTask extends AsyncTask<Void, Void, List<Section>> {

      @Override
      protected void onPreExecute() {
         progressDialog.show();
      }

      @Override
      protected List<Section> doInBackground(Void... args) {
         List<Section> sections = app.getParser().parse();
         return sections;
      }

      @Override
      protected void onPostExecute(List<Section> taskSectionList) {
         if (progressDialog.isShowing()) {
            progressDialog.dismiss();
         }
         if (!taskSectionList.isEmpty()) {
            app.getSectionList().clear();
            app.getSectionList().addAll(taskSectionList);            
            resetListItems(taskSectionList.get(0).getItems());            
            
            // Dla przycisku uruchamiającego przetwarzanie danych z kanału RSS należy
            // zresetować dane kontrolki Spinner i ustawić wybór na Daily Deals.
            // Ponieważ nie ma zmiennej na dane adaptera spinnerAdapter, trzeba
            // ponownie ustawić wszystkie opcje.
            sectionSpinner.setSelection(0);
            spinnerAdapter.clear();
            for (Section s : taskSectionList) {
               spinnerAdapter.add(s);
            }            
         } else {
            Toast.makeText(DealList.this, getString(R.string.deal_list_missing_data), Toast.LENGTH_LONG).show();
         }
      }
   }

   private class RetrieveImageTask extends AsyncTask<String, Void, Bitmap> {
      private ImageView imageView;

      public RetrieveImageTask(ImageView imageView) {
         this.imageView = imageView;
      }

      @Override
      protected Bitmap doInBackground(String... args) {
         Bitmap bitmap = app.retrieveBitmap(args[0]);
         return bitmap;
      }

      @Override
      protected void onPostExecute(Bitmap bitmap) {
         if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            app.getImageCache().put((Long) imageView.getTag(), bitmap);
            imageView.setTag(null);
         }
      }
   }
}