package org.przyklad.tapeta;

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

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;

import android.service.wallpaper.WallpaperService;
import android.view.SurfaceHolder;


public class Tapeta extends WallpaperService {
	private class MojSilnik extends Engine {
		
		private RendererGL rendererGl;
		private GL10 gl;
		private EGL10 egl;
		private EGLContext glc;
		private EGLDisplay wyswietlaczGl;
		private EGLSurface powierzchniaGl;

		private ExecutorService egzekutor;
		private Runnable polecenieRysowania;

		
		@Override
		public void onCreate(final SurfaceHolder uchwyt) {
		    super.onCreate(uchwyt);
		    egzekutor = Executors.newSingleThreadExecutor();

		    polecenieRysowania = new Runnable() {
		        public void run() {
		            rendererGl.onDrawFrame(gl);
		            egl.eglSwapBuffers(wyswietlaczGl, powierzchniaGl);
		            if (isVisible()
		                    && egl.eglGetError() != EGL11.EGL_CONTEXT_LOST) {
		                egzekutor.execute(polecenieRysowania);
		            }
		        }
		    };
		}


		@Override
		public void onDestroy() {
		    egzekutor.shutdownNow();
		    super.onDestroy();
		};


		@Override
		public void onSurfaceCreated(final SurfaceHolder uchwyt) {
		    super.onSurfaceCreated(uchwyt);
		    Runnable polecenieUtworzonaPowierzchnia = new Runnable() {
		        @Override
		        public void run() {
		            // Inicjacja środowiska OpenGL
		            egl = (EGL10) EGLContext.getEGL();
		            wyswietlaczGl = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
		            int[] wersja = new int[2];
		            egl.eglInitialize(wyswietlaczGl, wersja);
		            int[] specKonfig = { EGL10.EGL_RED_SIZE, 5,
		                EGL10.EGL_GREEN_SIZE, 6, EGL10.EGL_BLUE_SIZE,
		                5, EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
		            EGLConfig[] konfiguracje = new EGLConfig[1];
		            int[] numKonfig = new int[1];
		            egl.eglChooseConfig(wyswietlaczGl, specKonfig, konfiguracje,
		                1, numKonfig);
		            EGLConfig konfiguracja = konfiguracje[0];

		            glc = egl.eglCreateContext(wyswietlaczGl, konfiguracja,
		                EGL10.EGL_NO_CONTEXT, null);

		            powierzchniaGl = egl.eglCreateWindowSurface(wyswietlaczGl,
		                konfiguracja, uchwyt, null);
		            egl.eglMakeCurrent(wyswietlaczGl, powierzchniaGl, powierzchniaGl,
		                glc);
		            gl = (GL10) (glc.getGL());

		            // Inicjacja renderera
		            rendererGl = new RendererGL(Tapeta.this);
		            rendererGl.onSurfaceCreated(gl, konfiguracja);
		        }
		    };
		    egzekutor.execute(polecenieUtworzonaPowierzchnia);
		}


		@Override
		public void onSurfaceDestroyed(final SurfaceHolder uchwyt) {
		    Runnable poleceniePowierzchniaUsunieta = new Runnable() {
		        public void run() {
		            // Uwalnia zasoby zajęte przez środowisko OpenGL
		            egl.eglMakeCurrent(wyswietlaczGl, EGL10.EGL_NO_SURFACE,
		                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
		            egl.eglDestroySurface(wyswietlaczGl, powierzchniaGl);
		            egl.eglDestroyContext(wyswietlaczGl, glc);
		            egl.eglTerminate(wyswietlaczGl);

		        };
		    };
		    egzekutor.execute(poleceniePowierzchniaUsunieta);
		    super.onSurfaceDestroyed(uchwyt);
		}


		@Override
		public void onSurfaceChanged(final SurfaceHolder uchwyt,
		        final int format, final int szerokosc, final int wysokosc) {
		    super.onSurfaceChanged(uchwyt, format, szerokosc, wysokosc);
		    Runnable poleceniePowierzchniaZmieniona = new Runnable() {
		        public void run() {
		            rendererGl.onSurfaceChanged(gl, szerokosc, wysokosc);
		        };
		    };
		    egzekutor.execute(poleceniePowierzchniaZmieniona);
		}


		@Override
		public void onVisibilityChanged(final boolean widoczny) {
		    super.onVisibilityChanged(widoczny);
		    if (widoczny) {
		        egzekutor.execute(polecenieRysowania);
		    }
		}


		@Override
		public void onOffsetsChanged(final float xOffset,
		        final float yOffset, final float xOffsetKrok,
		        final float yOffsetKrok, final int xOffsetPiksela,
		        final int yOffsetPiksela) {
		    super.onOffsetsChanged(xOffset, yOffset, xOffsetKrok,
		            yOffsetKrok, xOffsetPiksela, yOffsetPiksela);
		    Runnable polecenieOffsetyZmienione = new Runnable() {
		        public void run() {
		            if (xOffsetKrok != 0f) {
		                rendererGl.ustawParalakse(xOffset - 0.5f);
		            }
		        };
		    };
		    egzekutor.execute(polecenieOffsetyZmienione);
		}

	}


    @Override
    public Engine onCreateEngine() {
        return new MojSilnik();
    }
}

