package com.manning.aip.media;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.media.ThumbnailUtils;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import static android.os.Environment.*;

/**
 * Przeglądanie zdjęć ze współużytkowanego katalogu /Pictures. Jeśli nie ma w nim
 * zdjęć, aplikacja wyświetla komunikat o błędzie. Dlatego należy umieścić w tym 
 * katalogu pliki graficzne.
 * 
 * @author Michael Galpin
 *
 */
public class ImageBrowserActivity extends Activity {
	
	private static final String LOG_TAG = "ImageBrowserActivity";
	
	// Siatka z wszystkimi zdjęciami
	private GridView grid;
	
	// Wybrane pliki
	private ArrayList<File> selectedFiles = new ArrayList<File>();
	
	// Obiekt klasy MediaPlayer do odtwarzania motywu muzycznego
	private MediaPlayer player;
	private ProgressDialog dialog;
	// Wszystkie zdjęcia.
	private List<File> imageFiles;
	// Pamięć podręczna na miniatury.
	private List<Bitmap> thumbs;
	// Maksymalna wielkość miniatur.
	private static final double MAX_DIMENSION = 200.0D;

    protected static final int NO_PICS = 19;
	
	private Handler loadingHandler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
		    if (msg.what == NO_PICS){
		        Toast.makeText(ImageBrowserActivity.this, R.string.empty_pics_msg, 
                        Toast.LENGTH_LONG).show();
                imageFiles = new ArrayList<File>(0);
                thumbs = new ArrayList<Bitmap>(0);
		    }
			grid.setAdapter(new GridAdapter());
			dialog.dismiss();
	        if (grid.getCount() == 0){
	        	LinearLayout container = 
	        		(LinearLayout) findViewById(R.id.container);
	        	container.removeAllViews();
	        	TextView t = new TextView(ImageBrowserActivity.this);
	        	t.setText(R.string.no_pics_err_msg);
	        	container.addView(t);
	        	Button btn = new Button(ImageBrowserActivity.this);
	        	btn.setText("Koniec");
	        	btn.setOnClickListener(new OnClickListener(){
					@Override
					public void onClick(View button) {
						ImageBrowserActivity.this.finish();
					}
	        	});
	        	container.addView(btn);
	        }    				
		}
	};
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.image_browser);

        grid = (GridView) findViewById(R.id.grid);

        // Przycisk do przechodzenia do następnej aktywności
        Button nxtBtn = (Button) findViewById(R.id.nxtBtn1);
        nxtBtn.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View view) {
				Intent i = 
					new Intent(ImageBrowserActivity.this, 
							AudioBrowserActivity.class);
				ArrayList<String> fileNamesList = 
					new ArrayList<String>(selectedFiles.size());
				for (File f : selectedFiles){
					try {
						fileNamesList.add(f.getCanonicalPath());
					} catch (IOException e) {
						Log.e(LOG_TAG, "Wyjątek przy dodawaniu nazw plików",e);
					}
				}
				i.putStringArrayListExtra("imageFileNames", fileNamesList);
				// Kopiowanie danych przekazanych do aktywności. Dane
				// przekazywane są do następnej aktywności.
				Intent req = getIntent();
				if (req != null && req.getExtras() != null){
					i.putExtras(req);
				}
				startActivity(i);
			}
		});   
        
    }

    // Odtwarza utworzy z katalogu assets/audio
    private void playThemeMusic() {
    	player = new MediaPlayer();
		AssetManager mgr = getResources().getAssets();
		String audioDir = "audio";
		try {
			final LinkedList<FileDescriptor> queue = 
				new LinkedList<FileDescriptor>();
			for (String song : mgr.list("audio")){
				queue.add(
						mgr.openFd(audioDir + "/" + song).getFileDescriptor());
			}
			playNextSong(queue);
			player.setOnCompletionListener(new OnCompletionListener(){
				@Override
				public void onCompletion(MediaPlayer mp) {
					try {
						playNextSong(queue);
					} catch (IOException e) {
						Log.e(LOG_TAG, "Wyjątek przy wczytywaniu piosenki",e);
					}
				}
			});
		} catch (IOException e) {
			Log.e(LOG_TAG, "Wyjątek przy wczytywaniu piosenki",e);
		}
	}

	private void playNextSong(LinkedList<FileDescriptor> queue) 
	throws IOException {
		if (!queue.isEmpty()){
			FileDescriptor song = queue.poll();
			player.setDataSource(song);
			player.prepare();
			player.start();
		}
	}
	
	// Nieużywana (dodana jako przykład)
	private void playThemeSong(){
		player = MediaPlayer.create(this, R.raw.constancy);
		player.start();
	}
	
	@Override
	public void onPause(){
		super.onPause();
		if (player != null && player.isPlaying()){
			player.pause();
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		if (player != null && player.isPlaying()){
			player.stop();
		}
		player.release();
	}

	@Override
	public void onResume() {
		super.onResume();
        // Ustawianie interfejsu użytkownika i odbiorników zdarzeń.
        // Wczytanie wszystkich zdjęć może chwilę potrwać, dlatego
		// wyświetlamy okno dialogowe z informacjami o postępie
        dialog = ProgressDialog.show(this, "", "Wczytywanie zdjęć");
        playThemeMusic();
		if (player != null){
			player.start();
		}
        Runnable loader = new Runnable(){
            @Override
            public void run() {
                // Pobieranie zdjęć z katalogu /Pictures
                File picturesDir = 
                    getExternalStoragePublicDirectory(DIRECTORY_PICTURES);
                if (picturesDir == null || picturesDir.list() == null || 
                        picturesDir.list().length == 0){
                    Message none = Message.obtain();
                    none.what = NO_PICS;
                    loadingHandler.sendMessage(none);
                    return;
                }
                int maxNumFiles;
                String[] nameArray = picturesDir.list();
                if (nameArray == null){
                    maxNumFiles = 0; 
                } else {
                    maxNumFiles = nameArray.length;
                }
                ArrayList<File> theFiles = new ArrayList<File>(maxNumFiles);
                if (maxNumFiles == 0) return;
                for (String fileName : nameArray){
                    File file = new File(picturesDir, fileName);
                    if (file.isFile()){
                        theFiles.add(file);
                    }
                }
                imageFiles = Collections.unmodifiableList(theFiles);
                ArrayList<Bitmap> tempThumbs = 
                    new ArrayList<Bitmap>(imageFiles.size());
                for (int i=0;i<imageFiles.size();i++){
                    Bitmap thumb = makeThumb(i);
                    if (thumb != null){
                        tempThumbs.add(thumb);
                    }
                }
                thumbs = Collections.unmodifiableList(tempThumbs);
                loadingHandler.sendMessage(Message.obtain());
            }
        };
        Thread loadingThread = new Thread(loader);
        loadingThread.start();
	}
	/**
	 * Tworzy miniaturę zdjęcia na określonej pozycji na liście.
	 * @param 	position		Pozycja zdjęcia na liście
	 * @return	Miniatura utworzona przez przycięcie zdjęcia
	 */
	private Bitmap makeThumb(int position){
		Log.d(LOG_TAG, "Tworzenie miniatury dla pozycji="+position);
		try{
			File imgFile = getImageFile(position);
			if (imgFile != null){
				Log.d(LOG_TAG, "Pobrano plik z pozycji="+position+" file="+
						imgFile.getAbsolutePath());
				InputStream stream = new FileInputStream(imgFile);
				Bitmap bm = BitmapFactory.decodeStream(stream);
	        	int imgWidth = bm.getWidth();
	        	int imgHeight = bm.getHeight();
	        	int max = Math.max(imgWidth, imgHeight);
	        	double scale = MAX_DIMENSION / max;
	        	int width = (int) (scale * imgWidth);
	        	int height = (int) (scale * imgHeight);
	        	Log.d(LOG_TAG, "Nowa szerokość=" + width);
	        	Log.d(LOG_TAG, "Nowa wysokość=" + height);
	        	// Przycina zdjęcia w celu utworzenia miniatury
	        	Bitmap thumb = 
	        		ThumbnailUtils.extractThumbnail(bm, width, height);
	        	// Aby przeskalować zdjęcie, użyj metody Bitmap.createScaledBitmap
	        	bm = null;
	        	return thumb;
			} else {
				Log.w(LOG_TAG, "Plik z pozycji="+position + " to null");
			}
		} catch (Exception e) {
			Log.e(LOG_TAG, "Wyjątek przy pobieraniu miniatury z " +
					"pozycji="+position, e);
		}
		Log.w(LOG_TAG, "Błąd przy generowaniu miniatury dla pozycji="+position);
		return null;
	}

	private File getImageFile(int position) {
		if (position > imageFiles.size()){
			return null;
		}
		return imageFiles.get(position);
	}
	// Niestandardowy adapter dla siatki ze zdjęciami
	private class GridAdapter extends BaseAdapter{
		
		@Override
		public int getCount() {
			return thumbs.size();
		}

		@Override
		public Object getItem(int position) {
			if (position > getCount()){
				return null;
			}
			return thumbs.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(final int position, View cell, ViewGroup parent) {
			Log.d(LOG_TAG, "Pobieranie komórki dla pozycji="+position);
			if (cell == null){
				LayoutInflater airPump = getLayoutInflater();
				cell = airPump.inflate(R.layout.grid_item, parent, false);
			}
			ViewHolder holder = (ViewHolder) cell.getTag();
			if (holder == null){
				holder = new ViewHolder(cell);
				cell.setTag(holder);
			}
			ImageView img = holder.img;
			Bitmap thumb = (Bitmap) getItem(position);
			if (thumb == null){
				Log.w(LOG_TAG, "Pusta miniatura dla pozycji="+position);
			} else {
				img.setLayoutParams(
						new LinearLayout.LayoutParams(thumb.getWidth(), 
								thumb.getHeight()));
				img.setImageBitmap(thumb);
			}
			final File file = getImageFile(position);
			final CheckBox cbox = holder.cbox;
			if (selectedFiles.contains(file)){
				cbox.setChecked(true);
			} else {
				cbox.setChecked(false);
			}
			cbox.setOnClickListener(new OnClickListener(){
				@Override
				public void onClick(View view) {
					
					if (selectedFiles.remove(file)){
						Log.d(LOG_TAG, "Usunięto plik:" + file.getName());
						cbox.setSelected(false);
					} else {
						selectedFiles.add(file);
						cbox.setSelected(true);
						Log.d(LOG_TAG, "Dodano plik:" + file.getName());
					}
				}
				
			});
			return cell;
		}
    }
    
	/**
	 * Stosowanie wzorca z klasą ViewHolder. Technika ta przydaje się do 
	 * zapisywania w pamięci podręcznej referencji do widoków, które mają
	 * być ustawiane dynamicznie.
	 */
   static class ViewHolder {
    	final ImageView img;
    	final CheckBox cbox;
    	ViewHolder(View cell){
    		img = (ImageView) cell.findViewById(R.id.thumb);
    		cbox = (CheckBox) cell.findViewById(R.id.cbox);
    	}
    }
}