package main

import (
    "github.com/veandco/go-sdl2/sdl"
    "github.com/veandco/go-sdl2/img"
    "github.com/veandco/go-sdl2/mix"
    "math"
)

import strings "strings"

// CharacterWidth is the width of the individual characters in the font
const CharacterWidth = 64
// CharacterHeight is the height of the individual characters in the font
const CharacterHeight = 128
// ScreenWidth is the width of the screen
const ScreenWidth = 1920 
// ScreenHeight is the height of the screen
const ScreenHeight = 1080 
// SpriteWidth is the running man sprite width
const SpriteWidth = 160 
// SpriteHeight is the running man sprite height
const SpriteHeight = 160 
// WindowTitle is the title of the main window
const WindowTitle = "Running Man"
var sineCounter = 0.05
// Message is the message that should run across the screen while the program is running
const Message = "Greetings birdie! We are the Birdie.date crew! " +
                //"I ported some old crap to GOLANG. " +
                //"Why? Because I can!  " +
                "Welcome one and all to the infamous Birdie.date channel. " +
                "Where only the coolest birdies hang out! " +
                "Birdie.date connects via quakenet (1200 BAUD). " +
                "Birdie.date is the best birdie related irc-channel! " +
                "we have a great bot and interesting discussions. " +
                "Programming by ReturnsVoid. " + 
                "Graphics by Alcor and Preox. " +
                "Music by Alcor. " + 
                "Made at birdie29. " + 
                "Greetz to Dunz0r, firearrow, risqa, tek-ti, dr.rabies, diskmaskinstillverkning."

func main() {

    var msg = strings.ToLower(Message)

    if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
        panic(err)
    }
    defer sdl.Quit()

    if err := img.Init(img.INIT_PNG); err != 2 {
        panic(err)
    }
    defer img.Quit()

    // This needs to happen before mix.Init if sdl-mixer is version 2.0.2
    if err := mix.OpenAudio(mix.DEFAULT_FREQUENCY, mix.DEFAULT_FORMAT, mix.DEFAULT_CHANNELS, mix.DEFAULT_CHUNKSIZE); err != nil {
        panic(err)
    }
    defer mix.CloseAudio()

    if err := mix.Init(mix.INIT_MP3); err != nil {
        panic(err)
    }
    defer mix.Quit()

    window, err := sdl.CreateWindow(WindowTitle, sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, ScreenWidth, ScreenHeight, sdl.WINDOW_SHOWN)
    if err != nil {
        panic(err)
    }
    window.SetFullscreen(sdl.WINDOW_FULLSCREEN)
    defer window.Destroy()

    renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED | sdl.RENDERER_PRESENTVSYNC)
    if err != nil {
        panic(err)
    }
    defer renderer.Destroy()

    backgroundTexture := loadPNG(renderer, "resources/rosa.png", false)
    defer backgroundTexture.Destroy()

    fontTexture := loadPNG(renderer, "resources/font3.png", true)
    defer fontTexture.Destroy()

    spriteTexture := loadPNG(renderer, "resources/birdie2.png", true)
    defer spriteTexture.Destroy()

    music, err := mix.LoadMUS("resources/lifeofaslime.xm")
    if err != nil {
        panic(err)
    }
    defer music.Free()

    if err := music.Play(-1); err != nil {
        panic(err)
    }
    
    var spriteFrames [12]sdl.Rect
    spriteFrames[0] = sdl.Rect{X:0, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[1] = sdl.Rect{X:SpriteWidth*2, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[2] = sdl.Rect{X:SpriteWidth*3, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[3] = sdl.Rect{X:SpriteWidth*4, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[4] = sdl.Rect{X:SpriteWidth*5, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[5] = sdl.Rect{X:SpriteWidth*6, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[6] = sdl.Rect{X:SpriteWidth*7, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[7] = sdl.Rect{X:SpriteWidth*8, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[8] = sdl.Rect{X:SpriteWidth*9, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[9] = sdl.Rect{X:SpriteWidth*10, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[10] = sdl.Rect{X:SpriteWidth*11, Y:0, W:SpriteWidth, H:SpriteHeight}
    spriteFrames[11] = sdl.Rect{X:SpriteWidth*12, Y:0, W:SpriteWidth, H:SpriteHeight}

    running := true
    spriteFrameCounter := 0
	var posCounter int32 = -200
    textFrameCounter := -1000
    for running {
        event := sdl.PollEvent()
        switch eventType := event.(type) {
        case *sdl.QuitEvent:
            running = false
        case *sdl.KeyboardEvent:
            switch eventType.Keysym.Sym {
            case sdl.K_ESCAPE:
                running = false
            }
        }

        renderer.SetDrawColor(255, 255, 255, 255)
        renderer.Clear()

        // Render background
        renderer.Copy(backgroundTexture, nil, nil)

        // Render text
        renderScrollingTextString(renderer, fontTexture, ScreenWidth-textFrameCounter, 200, msg)

        // Render Birdie-slime
        var spriteXPos int32 = 380
        renderer.Copy(spriteTexture, &spriteFrames[spriteFrameCounter/12], &sdl.Rect{X: spriteXPos, Y: 600, W: SpriteWidth, H: SpriteHeight})
        renderer.Copy(spriteTexture, &spriteFrames[spriteFrameCounter/12], &sdl.Rect{X: spriteXPos+300, Y: 600, W: SpriteWidth, H: SpriteHeight})
        renderer.Copy(spriteTexture, &spriteFrames[spriteFrameCounter/12], &sdl.Rect{X: spriteXPos+600, Y: 600, W: SpriteWidth, H: SpriteHeight})
        renderer.Copy(spriteTexture, &spriteFrames[spriteFrameCounter/12], &sdl.Rect{X: spriteXPos+900, Y: 600, W: SpriteWidth, H: SpriteHeight})

        renderer.Present()

        spriteFrameCounter, posCounter, textFrameCounter, sineCounter = increaseCounters(spriteFrameCounter, posCounter, textFrameCounter, sineCounter)
    }
}

func renderScrollingTextString(renderer *sdl.Renderer, fontTexture *sdl.Texture, xPos int, yPos int, scrollingText string) {
    for charCount, char := range scrollingText {
        var characterXPos = xPos + charCount*CharacterWidth
        var characterYPos = yPos + int(30*math.Sin((float64(charCount)-sineCounter)/2))
        drawCharacter(renderer, fontTexture, characterXPos, characterYPos, string(char))
    }
}

func drawCharacter(renderer *sdl.Renderer, fontTexture *sdl.Texture, xPos int, yPos int, character string) {
    if (len(character) != 1) {
        panic("Cannot handle more than one character!")
    }
    
    const charMap string = "abcdefghijklmnopqrstuvwxyz0123456789\"'(),.;:+-!?"
    var index = strings.Index(charMap, character)
    if (index >= 0) {
        var characterSprite = sdl.Rect{X:int32(index*CharacterWidth), Y:0, W: CharacterWidth, H:CharacterHeight}
        var targetRect = sdl.Rect{X: int32(xPos),Y: int32(yPos), W: CharacterWidth, H: CharacterHeight}
        renderer.Copy(fontTexture, &characterSprite, &targetRect)
    }
}

func loadPNG(renderer *sdl.Renderer, path string, setColorKey bool) *sdl.Texture {
    png, err := img.Load(path)
    if err != nil {
        panic(err)
    }

    if setColorKey {
        png.SetColorKey(true, sdl.MapRGB(png.Format, 0, 255, 255))
    }

    texture, err := renderer.CreateTextureFromSurface(png)
    if err != nil {
        panic(err)
    }
    png.Free()

    return texture
}

func increaseCounters(spriteFrameCounter int, posCounter int32, textFrameCounter int, sineCounter float64) (int, int32, int, float64) {
    spriteFrameCounter++
    if spriteFrameCounter/12 >= 12 {
        spriteFrameCounter = 0
    }

    posCounter -= 5
    if posCounter <= -SpriteWidth {
        posCounter = ScreenWidth
    }

    if ((len(Message)*CharacterWidth) - (textFrameCounter - ScreenWidth) <= 0) {
        textFrameCounter = 0
    } else {
        textFrameCounter += 5
    }
    sineCounter += 0.08

    return spriteFrameCounter, posCounter, textFrameCounter, sineCounter
}
