/*
 * Copyright (C) 2011 Michael Imamura
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.lugatgt.zoogie.present;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.os.Bundle;


/**
 * Base class for presentations.
 * @author Michael Imamura
 */
public abstract class Presentation {
    
    private static final String PROP_PFX = "presentation.";
    private static final String PROP_INDEX = PROP_PFX + "index";
    
    private List<Slide> slides;
    private Map<String, Slide> nameToSlide;
    
    private OnIndexChangedListener indexChangedListener;
    
    private int idx;
    
    // CONSTRUCTORS ////////////////////////////////////////////////////////////
    
    /**
     * Constructor.
     * @param initSlides The initial set of slides (may not be null, may not be empty).
     */
    public Presentation(Slide[] initSlides) {
        if (initSlides == null || initSlides.length == 0) {
            throw new IllegalArgumentException("Initial slides must not be empty.");
        }
        
        slides = Arrays.asList(initSlides);
        
        nameToSlide = new HashMap<String, Slide>();
        for (Slide initSlide : initSlides) {
            nameToSlide.put(initSlide.getName(), initSlide);
        }
        
        idx = 0;
    }
    
    // FIELD ACCESS ////////////////////////////////////////////////////////////
    
    /**
     * Set the callback for when the current slide index changes.
     * @param listener The listener (may be null).
     */
    public void setOnIndexChangedListener(OnIndexChangedListener listener) {
        indexChangedListener = listener;
    }
    
    // SLIDES //////////////////////////////////////////////////////////////////
    
    public CharSequence[] getSlideTitles(Context ctx) {
        CharSequence[] titles = new CharSequence[slides.size()];
        for (int i = 0; i < slides.size(); i++) {
            titles[i] = slides.get(i).getTitle(ctx);
        }
        return titles;
    }
    
    public Slide getCurrentSlide() {
        return slides.get(idx);
    }
    
    public int getCurrentSlideIndex() {
        return idx;
    }
    
    public boolean isAtBeginning() {
        return idx == 0;
    }
    
    public boolean isAtEnd() {
        return idx == slides.size() - 1;
    }
    
    public int getSlideCount() {
        return slides.size();
    }
    
    public Slide jumpTo(int i) {
        if (i < 0 || i >= slides.size()) {
            throw new ArrayIndexOutOfBoundsException(
                "Slide index must be 0 <= idx < " + slides.size());
        }
        Slide oldSlide = getCurrentSlide();
        int oldIdx = idx;
        idx = i;
        fireOnIndexChanged(oldSlide, oldIdx, true);
        return getCurrentSlide();
    }
    
    public Slide prev() {
        if (idx == 0) {
            return null;
        } else {
            Slide oldSlide = getCurrentSlide();
            idx--;
            fireOnIndexChanged(oldSlide, idx + 1, true);
            return getCurrentSlide();
        }
    }
    
    public Slide next() {
        if (idx == slides.size() - 1) {
            return null;
        } else {
            Slide oldSlide = getCurrentSlide();
            idx++;
            fireOnIndexChanged(oldSlide, idx - 1, false);
            return getCurrentSlide();
        }
    }
    
    // PERSISTANCE /////////////////////////////////////////////////////////////
    
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        idx = savedInstanceState.getInt(PROP_INDEX);
    }
    
    public void onSaveInstanceState(Bundle outState) {
        outState.putInt(PROP_INDEX, idx);
    }
    
    // EVENTS //////////////////////////////////////////////////////////////////
    
    protected void fireOnIndexChanged(Slide oldSlide, int oldIndex, boolean immediate) {
        if (indexChangedListener != null) {
            if (oldIndex != idx) {
                indexChangedListener.onAfterIndexChanged(oldSlide, oldIndex, immediate);
            }
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // OnIndexChangedListener
    
    public interface OnIndexChangedListener {
        
        /**
         * Called when the current slide index changes.
         * <p>
         * Implementations can find the new slide and slide index by calling
         * {@link #getCurrentSlide()} and {@link #getCurrentSlideIndex()},
         * respectively.
         * 
         * @param oldSlide The old slide (may be null).
         * @param oldIndex The old slide index.
         * @param immediate true if navigating to the new slide immediately;
         *                  (i.e., should not play any animations).
         */
        void onAfterIndexChanged(Slide oldSlide, int oldIndex, boolean immediate);
        
    }
    
}

@@ -1090,21 +1090,23 @@
 ng, 
-Slide
+Integer
 %3E nameTo
 Slid
@@ -1101,21 +1101,21 @@
 %3E nameTo
-Sli
+In
 de
+x
 ;%0A    %0A 
@@ -1688,21 +1688,21 @@
   nameTo
-Sli
+In
 de
+x
  = new H
@@ -1716,21 +1716,23 @@
 String, 
-Slide
+Integer
 %3E();%0A   
@@ -1741,16 +1741,69 @@
    for (
+int i = 0; i %3C initSlides.length; i++) %7B%0A            
 Slide in
@@ -1810,17 +1810,17 @@
 itSlide 
-:
+=
  initSli
@@ -1814,35 +1814,36 @@
 ide = initSlides
-) %7B
+%5Bi%5D;
 %0A            nam
@@ -1845,21 +1845,21 @@
   nameTo
-Sli
+In
 de
+x
 .put(ini
@@ -1877,24 +1877,16 @@
 ame(), i
-nitSlide
 );%0A     
@@ -3394,32 +3394,318 @@
 e();%0A    %7D%0A    %0A
+    public Slide jumpTo(String name) %7B%0A        Integer newIdx = nameToIndex.get(name);%0A        if (newIdx == null) %7B%0A            throw new IllegalArgumentException(%22Unable to find a slide named %5C%22%22 + name + '%22');%0A        %7D else %7B%0A            return jumpTo(newIdx);%0A        %7D%0A    %7D%0A    %0A
     public Slide

Add ability to jump to a slide by name.