/***
 * Wyciąg z książki "Hello, Android!",
 * opublikowanej przez wydawnictwo Helion S.A.
 * Niniejszy kod jest chroniony prawami autorskimi. Nie może zostać wykorzystany do utworzenia 
 * materiałów treningowych, kursów, książek, artykułów, itp. Prosimy o kontakt w razie
 * pojawienia się wątpliwości.
 * Nie gwarantujemy, że niniejszy kod będzie się nadawał do jakiegokolwiek celu. 
 * Więcej informacji można znaleźć na stronie http://www.pragmaticprogrammer.com/titles/eband.
***/
package org.przyklad.translator;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;

public class Translator extends Activity {
    private Spinner zSpinner;
    private Spinner naSpinner;
    private EditText tekstOryg;
    private TextView tekstTlum;
    private TextView tekstPonTlum;

    private TextWatcher obserwatorTekstu;
    private OnItemSelectedListener nasluchWyboruElementu;

    private Handler watekGui;
    private ExecutorService watekTlum;
    private Runnable zadanieAktualizacja;
    private Future trwajaceTlum;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);
        inicjacjaWatkowania();
        znajdzWidoki();
        ustawAdaptery();
        ustawObiektyNasluchujace();
    }
    
    @Override
    protected void onDestroy() {
       // Wyłącza tutaj dodatkowe wątki
       watekTlum.shutdownNow();
       super.onDestroy();
    }
                 
    /** Generuje uchwyt dla wszystkich elementów interfejsu użytkownika */
    private void znajdzWidoki() {
        zSpinner = (Spinner) findViewById(R.id.z_jezyka);
        naSpinner = (Spinner) findViewById(R.id.na_jezyk);
        tekstOryg = (EditText) findViewById(R.id.tekst_oryginal);
        tekstTlum = (TextView) findViewById(R.id.tekst_przetlumaczony);
        tekstPonTlum = (TextView) findViewById(R.id.tekst_pon_przetlumaczony);
    }
   
    /** Definiuje źródło danych dla obiektów typu Spinner */
    private void ustawAdaptery() {
        // Lista danych dla obiektu Spinner pochodzi z zasobu,
        // Interfejs użyt. obiektu Spinner korzysta ze standardowych układów graf.
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.jezyki,
            android.R.layout.simple_spinner_item);
            adapter.setDropDownViewResource(
                android.R.layout.simple_spinner_dropdown_item);
            zSpinner.setAdapter(adapter);
            naSpinner.setAdapter(adapter);

        // Automatycznie wybiera dwa elementy w obiektach typu Spinner
        zSpinner.setSelection(21); // Polski (pl)
        naSpinner.setSelection(9); // Francuski (fr)
    }

    /** Konfiguruje procedury obsługi zdarzeń związanych z interfejsem użytkownika */
    private void ustawObiektyNasluchujace() {
        // Definiuje obiekty nasłuchujące zdarzeń
        obserwatorTekstu = new TextWatcher() {
            public void beforeTextChanged(CharSequence s, int start,
                    int licz, int po) {
                /* Nic nie rób */
        }
        public void onTextChanged(CharSequence s, int start,
                int przed, int licz) {
            aktualizacjaKolejki(1000 /* millisekundy */);
        }
        public void afterTextChanged (Editable s) {
            /* Nic nie rób */
        }
    };
    nasluchWyboruElementu = new OnItemSelectedListener() {
        public void onItemSelected(AdapterView rodzic, View v,
            int pozycja, long id) {
        aktualizacjaKolejki(200 /* millisekundy */);
    }
    public void onNothingSelected(AdapterView rodzic) {
        /* Nic nie rób */
    }
   };

   // Rejestruje obiekty nasłuchujące widżetów graficznego interfejsu użytkownika
   tekstOryg.addTextChangedListener(obserwatorTekstu);
   zSpinner.setOnItemSelectedListener(nasluchWyboruElementu);
   naSpinner.setOnItemSelectedListener(nasluchWyboruElementu);
  }

    /**
     * Inicjacja wielowątkowości. Wygenerowane zostają dwa wątki: 1) Wątek głównego
     * graficznego interfejsu użytkownika, już uruchomiony przez system Android,
     * oraz 2) Wątek tłumaczenia, który zostaje zapoczątkowany za pomocą egzekutora.
     */
    private void inicjacjaWatkowania() {
        watekGui = new Handler();
        watekTlum = Executors.newSingleThreadExecutor();
                	 
        // To zadanie odpowiada za tłumaczenie oraz aktualizację ekranu
        zadanieAktualizacja = new Runnable() {
            public void run() {
                // Pobiera tekst do tłumaczenia
                String oryginal = tekstOryg.getText().toString().trim();
                	 
                // Anuluje poprzednie tłumaczenie, jeśli takie było
                if (trwajaceTlum != null)
                    trwajaceTlum.cancel(true);
                	 
                // Zajmuje się prostymi przypadkami
                if (oryginal.length() == 0) {
                    tekstTlum.setText(R.string.pusty);
                	tekstPonTlum.setText(R.string.pusty);
                } else {
                    // Niech użytkownik wie, że coś się dzieje
                    tekstTlum.setText(R.string.tlumaczenie);
                    tekstPonTlum.setText(R.string.tlumaczenie);
                	 
                    // Rozpocznij tłumaczenie, ale nie czekaj
                    try {
                      ZadanieTlum zadanieTlumaczenia = new ZadanieTlum(
                        Translator.this, // referencja do aktywności                             
                        oryginal, // tekst oryginalny
                        wezJezyk(zSpinner), // z języka
                        wezJezyk(naSpinner) // na język
                      );
                      trwajaceTlum = watekTlum.submit(zadanieTlumaczenia);
                    } catch (RejectedExecutionException e) {
                	  // Nie można rozpocząć nowego zadania
                	  tekstTlum.setText(R.string.tlumaczenie_blad);
                	  tekstPonTlum.setText(R.string.tlumaczenie_blad);
                	}
                }
            }
        };
    }
                               
    /** Odczytuje kod języka z bieżącego elementu w obiekcie Spinner */
    private String wezJezyk(Spinner spinner) {
        String wynik = spinner.getSelectedItem().toString();
        int lrodzic = wynik.indexOf('(' );
        int prodzic = wynik.indexOf(')' );
        wynik = wynik.substring(lrodzic + 1, prodzic);
        return wynik;
    }

    /** Żąda rozpoczęcia aktualizacji po krótkim opóźnieniu */
    private void aktualizacjaKolejki(long opoznienieMillis) {
        // Anuluje poprzednią aktualizację, jeśli nie została jeszcze rozpoczęta
        watekGui.removeCallbacks(zadanieAktualizacja);
        // Rozpoczyna aktualizację, jeśli nic się nie będzie działo przez kilka ms
        watekGui.postDelayed(zadanieAktualizacja, opoznienieMillis);
    }

    /** Modyfikuje tekst na ekranie (wywoływane z drugiego wątku) */
    public void ustawPrzetlumaczone(String tekst) {
        guiUstawTekst(tekstTlum, tekst);
    }

    /** Modyfikuje tekst na ekranie (wywoływane z drugiego wątku) */
    public void ustawPonowniePrzetlum(String tekst) {
        guiUstawTekst(tekstPonTlum, tekst);
    }

    /** Wszystkie zmiany w interfejsie graficznym muszą zostać dokonane w wątku GUI */
    private void guiUstawTekst(final TextView widok, final String tekst) {
        watekGui.post(new Runnable() {
            public void run() {
                widok.setText(tekst);
            }
        });
    } 
}
