package global

import "log"
import "os"
import "math"

import al "gitlab.com/beoran/al5go/al"

type FPS struct {
    FPS     float64
    Now     float64
    Time    float64
    Show    bool
}



type State struct {
    Log         * log.Logger        
    Display     * al.Display
    Fullscreen    bool
    W             int
    H             int  
    HaveAudio     bool
    HaveTouch     bool
    HaveJoystick  bool
    Done          bool
    DefaultFont * al.Font
    TTF         * al.Font
    Colors        map[string](al.Color)
    Queue       * al.EventQueue
    FPS           
    Frames        int
    Joysticks    [] * al.Joystick
//  Map           tile.Map
//  MapID         store.ID
//  area.Area
//  camera.Camera
//  Sprites       sprite.List
//  ScriptEngine  raku.Runtime
//  zori.Console
//  zori.State
//  Actor area.Thing
}

func (ms * State) Hf() float32 {
    return float32(ms.H)
}

func (ms * State) Wf() float32 {
    return float32(ms.W)
}

func (ms * State) LogIfFail(ok bool, text string) bool {
    if !ok { 
        ms.Log.Printf("%s", text)
    }
    return ok
}

func (ms * State) SetupJoysticks() {
    if (!ms.HaveJoystick) {
        return 
    }
    
    ms.Joysticks = make([]*al.Joystick, 0)
    
    num := al.GetNumJoysticks()
    
    
    ms.Log.Printf("Found %d joysticks.\n", num)
    
    for i:= 0; i < num; i ++ {
        joy := al.GetJoystick(i)
        ms.Joysticks = append(ms.Joysticks, joy)
        ms.Log.Printf("Joystick nr %d, name %s", i, joy.GetName())
        snum := joy.GetNumSticks()
        bnum := joy.GetNumButtons()
        ms.Log.Printf("%d sticks and %d buttons", snum, bnum)        
    }
    
    ms.Queue.RegisterEventSource(al.JoystickEventSource())    
}

func (ms * State) InstallAllegro() bool {
    ms.Log = log.New(os.Stdout, "ebsengine: ", log.Lshortfile)
    res := ms.LogIfFail(al.InstallSystem(), "Could not install Allegro")
    res = res && ms.LogIfFail(al.InstallKeyboard(), "Could not install Keyboard")
    res = res && ms.LogIfFail(al.InstallMouse(), "Could not install mouse")
    al.InitFontAddon()
    res = res && ms.LogIfFail(al.InitTTFAddon(), "Could not init TTF addon")
    res = res && ms.LogIfFail(al.InitPrimitivesAddon(), "Could not init primitives addon")

    if res {
        ms.HaveTouch    = al.InstallTouchInput()
        ms.HaveJoystick = al.InstallJoystick()
        ms.HaveAudio    = al.InstallAudio()
        ms.HaveAudio    = ms.HaveAudio && al.InitAcodecAddon()
    }

    ms.Queue = al.CreateEventQueue()
    
    ms.SetupJoysticks()
    
    
    return res
}

func (ms * State) OpenDisplay(w, h int, title string, fullscreen bool) * al.Display {
    ms.Fullscreen = fullscreen
    ms.W          = w
    ms.H          = h
    flags := 0
    // Use full screen mode if needed.
    if fullscreen {
        flags = al.FULLSCREEN // | GENERATE_EXPOSE_EVENTS
    } else {
        al.SetNewDisplayFlags(flags)
    }
    // Create a window to display things on: 640x480 pixels.
    display := al.CreateDisplay(w, h)
    display.Resize(w, h)
    if !(fullscreen) {
        display.SetWindowTitle(title)
    }
    ms.Display = display
    
    ms.Queue.RegisterEventSource(al.GetKeyboardEventSource())
    ms.Queue.RegisterEventSource(al.GetMouseEventSource())
    ms.DefaultFont = al.CreateBuiltinFont()    
    
    ms.FPS.Time = al.Time()
    
    return display
}

func (ms * State) ScaleDisplay() { 
   real_w   := ms.Display.Width()
   real_h   := ms.Display.Height()
   scale_x  := real_w / ms.W
   scale_y  := real_h / ms.H
   scale    := scale_y
   
   if scale_x < scale_y {
        scale = scale_x
   }
   offset_x := (real_w  - (ms.W * scale)) / 2
   offset_y := (real_h  - (ms.H * scale)) / 2
   
   trans    := al.CreateIdentityTransform()   
   /* Draw black bars to cover the usused areas. */
   black := al.MapRGB(0,0,0)
   
   if (offset_y > 0) { 
        al.DrawFilledRectangleInt(-offset_x , -offset_y, real_w, 0, black)
        al.DrawFilledRectangleInt(-offset_x , ms.H, real_w, ms.H +offset_y, black)
   }
   if (offset_x > 0) { 
        al.DrawFilledRectangleInt(-offset_x , -offset_y, 0, real_h, black)
        al.DrawFilledRectangleInt(ms.W , -offset_y,  ms.W + offset_x, real_h, black)
   }
   
   trans.ScaleInt(scale, scale).TranslateInt(offset_x, offset_y).Use()
   /* al.SetClippingRectangle(offset_x, offset_y, ms.W, ms.H); */
}

func (ms * State) DrawFPS() {
    white := al.MapRGB(255,255,255)
    black := al.MapRGB(0,0,255)    
    al.DrawFilledRectangleInt(10, 10, 100, 10 + ms.DefaultFont.LineHeight(),black)
    ms.DefaultFont.DrawTextf(white, 10.0, 10.0, al.ALIGN_LEFT, "FPS: %d", int(ms.FPS.FPS))
}

func (ms * State) UpdateFrames() {
    ms.Frames++
    now := al.Time()
    if (now - ms.FPS.Time) >= 1.0 {
        realfps := float64(ms.Frames) / (now - ms.FPS.Time)
        /* Display and use a rounded value for FPS, the number after the comma is normally due to jitter anyway. */
        ms.FPS.FPS = math.Floor(realfps + 0.5)
        /* A little trick, to prevent jerkiness, keep half the frames; and half the time  */
        ms.Frames  = ms.Frames / 2
        ms.FPS.Time = now - 0.5
    }
}


func (ms * State) Draw() {
    ms.DrawFPS()
    yellow := al.MapRGB(255, 255, 0)
    al.DrawFilledCircle(30.0, 40.0, 15.0, yellow) 
    al.FlipDisplay()
}

func (ms * State) Load() {
    
}

func (ms * State) Run() {
    ms.Load()
    
    for !ms.Done {
        ms.Draw()
        ms.HandleEvents()
        ms.UpdateFrames()
    }
}


func (ms * State) HandleEvents() {
    for event, ok := ms.Queue.GetNextEvent() ; ok ; event, ok = ms.Queue.GetNextEvent() {
        ms.HandleEvent(event.Event())
    }
}


func (ms * State) HandleEvent(event al.Event) {
    switch uevent := event.(type) {
        case *al.KeyboardEvent: ms.HandleKeyboardEvent(uevent)
        default: break
    }

}

func (ms * State) HandleKeyboardEvent(event * al.KeyboardEvent ) {
    if (event.Keycode() == al.KEY_ESCAPE) {
        ms.Done = true
    }
}