#!/bin/sh
#\
exec wish "$0" "$@"

 
# window
set title_text "Level Editor for Bubble"
wm title . $title_text
wm iconname . "Level Editor"
#wm geometry . 800x600
wm resizable . 0 0

# globals
set datapath "images/editor"
set filename ""
set version "0.9.6"

set show_grid 1

set field_height 11
set field_width 16
set size_object 20

set fishes 0
set snakes 0
set sharks 0
set stars 0
set maxfishes 3
set diamonds 3
set background 1
set score 2500

set object_current 2
set object_min 1
set object_max 7
set object_default 2

set text(fishes) "Number of Fishes:"
set default(fishes) 0
set from(fishes) 0
set to(fishes) 20
set text(snakes) "Number of Snakes:"
set default(snakes) 0
set from(snakes) 0
set to(snakes) 20
set text(sharks) "Number of Sharks:"
set default(sharks) 0
set from(sharks) 0
set to(sharks) 20
set text(stars) "Number of Stars:"
set default(stars) 0
set from(stars) 0
set to(stars) 20
set text(maxfishes) "Fishes Maximum:"
set default(maxfishes) 3
set from(maxfishes) 0
set to(maxfishes) 20
set text(diamonds) "Number of Diamonds:"
set default(diamonds) 3
set from(diamonds) 0
set to(diamonds) 20
set text(score) "Level Time:"
set default(score) 2500
set from(score) 1000
set to(score) 9000
set text(background) "Background"
set default(background) 1
set from(background) 1
set to(background) 10


# images
# image surface
set image_surface [image create photo]

# images background
for {set i 1} {$i <= $to(background)} {incr i} {
    set image_background($i) [image create photo -file [format "%s/%s" $datapath "grounds/grnd_$i.gif"]]
}

# images object
set image_object(0) [image create photo -file [format "%s/%s" $datapath "objects/delete.gif"]]
set image_object(1) [image create photo -file [format "%s/%s" $datapath "objects/rock.gif"]]
set image_object(2) [image create photo -file [format "%s/%s" $datapath "objects/stone.gif"]]
set image_object(3) [image create photo -file [format "%s/%s" $datapath "objects/diamond.gif"]]
set image_object(4) [image create photo -file [format "%s/%s" $datapath "objects/ball_b.gif"]]
set image_object(5) [image create photo -file [format "%s/%s" $datapath "objects/ball_p.gif"]]
set image_object(6) [image create photo -file [format "%s/%s" $datapath "objects/dyn_r.gif"]]
set image_object(7) [image create photo -file [format "%s/%s" $datapath "objects/dyn_p.gif"]]


#######################################################################################

# menu
menu .menuBar -tearoff 0
.menuBar add cascade -menu .menuBar.file -label "File" -underline 0
.menuBar add cascade -menu .menuBar.edit -label "Edit" -underline 0
.menuBar add cascade -menu .menuBar.options -label "Options" -underline 0
.menuBar add cascade -menu .menuBar.help -label "Help" -underline 0

# menu file
menu .menuBar.file -tearoff 0
.menuBar.file add command -label "New" -command "new" -underline 0 -accelerator "Ctrl+N"
bind . <Control-n> "new"
.menuBar.file add command -label "Open ..." -command "openAs" -underline 0 -accelerator "Ctrl+O"
bind . <Control-o> "openAs"
.menuBar.file add command -label "Save as ..." -command "saveAs" -underline 0
.menuBar.file add command -label "Save" -command "save" -underline 0 -accelerator "Ctrl+S"
bind . <Control-s> "save"
.menuBar.file add sep
.menuBar.file add command -label "Quit" -command "quit" -underline 0 -accelerator "Ctrl+Q"
bind . <Control-q> "quit"

# menu edit
menu .menuBar.edit -tearoff 0
.menuBar.edit add command -label "Clear All" -command "clearObjects" -underline 0 -accelerator "Ctrl+A"
bind . <Control-a> "clearObjects"

# menu options
menu .menuBar.options -tearoff 0
.menuBar.options add check -label "Grid" -variable show_grid -command "showGrid"

# menu help
menu .menuBar.help -tearoff 0
.menuBar.help add command -label "About..." -command "aboutBox" -underline 0

# add menu
. configure -menu .menuBar


#######################################################################################

# field
frame .field

# objects
frame .field.objects

# buttons
set i 0
radiobutton .field.objects.$i -value $i -image $image_object($i) -indicatoron 0 -variable object_current
.field.objects.$i configure -selectcolor [.field.objects.$i cget -background]
pack .field.objects.$i -side left -padx 20

for {set i 1} {$i <= $object_max} {incr i} {
    radiobutton .field.objects.$i -value $i -image $image_object($i) -indicatoron 0 -variable object_current
    .field.objects.$i configure -selectcolor [.field.objects.$i cget -background]
    pack .field.objects.$i -side left
}

# field
canvas .field.c -height 220 -width 320
bind .field.c <B1-Motion> "paintObject %x %y"
bind .field.c <ButtonPress-1> "paintObject %x %y"
bind .field.c <ButtonPress-2> "nextObject"
bind .field.c <B3-Motion> "deleteObject %x %y"
bind .field.c <ButtonPress-3> "deleteObject %x %y"

# add surface image
.field.c create image 1 1 -image $image_surface -anchor nw
$image_surface copy $image_background($from(background))

set xx 123
# background
frame .field.background
button .field.background.button1 -text "<" -command "prevBackground"
label .field.background.label1 -text $text(background)
button .field.background.button2 -text ">" -command "nextBackground"
pack .field.background.button1 .field.background.label1  .field.background.button2 -side left

pack .field.objects -side top -expand yes -pady 10
pack .field.c -side top -expand yes
pack .field.background -side top -pady 20

# create grid
for {set j 0} {$j < $field_height} {incr j} {
    for {set i 0} {$i < $field_width} {incr i} {
        set x1 [expr ($size_object*$i)+1]
        set y1 [expr ($size_object*$j)+1]
        set x2 [expr $x1+$size_object]
        set y2 [expr $y1+$size_object]

        set grids($i,$j) [.field.c create rect $x1 $y1 $x2 $y2 -width 1]
            #.field.c bind $grids($i,$j) <Any-Enter> "enterField .field.c"
            #.field.c bind $grids($i,$j) <Any-Leave> "leaveField .field.c"
            #.field.c addtag config withtag $grids($i,$j)
    }
}

#######################################################################################

# level options
frame .config
pack .field .config -side left -expand yes -padx 20 -pady 20

# title
label .config.title -text "Level Options:"
pack .config.title -side top -padx 20 -pady 10

# set options
foreach i {fishes snakes sharks stars maxfishes diamonds} {
    frame .config.$i
    label .config.$i.label1 -text $text($i) -width 20 -anchor w
    scale .config.$i.scale1 -orient horizontal -length 150 -from $from($i) -to $to($i) -tickinterval 5 -variable $i -command "wasEdit2"
    bind .config.$i.scale1 <1> "wasEdit3 %y"
    bind .config.$i.scale1 <2> "wasEdit3 %y"
    pack .config.$i.label1 -side left
    pack .config.$i.scale1 -side right
    pack .config.$i  -side top
}

# set time
set i score
frame .config.$i
label .config.$i.label1 -text $text($i) -width 12 -anchor w
scale .config.$i.scale1 -orient horizontal -length 210 -from $from($i) -to $to($i) -tickinterval 8000 -resolution 100 -variable $i -command "wasEdit2"
bind .config.$i.scale1 <1> "wasEdit3 %y"
bind .config.$i.scale1 <2> "wasEdit3 %y"
pack .config.$i.label1 -side left
pack .config.$i.scale1 -side right
pack .config.$i  -side top


#######################################################################################

# set defaults
proc setDefaults {} {
    global fishes snakes sharks stars
    global maxfishes diamonds score
    global background
    global object_current object_default
    global default
    global should_save

    set fishes $default(fishes)
    set snakes $default(snakes)
    set sharks $default(sharks)
    set stars $default(stars)
    set maxfishes $default(maxfishes)
    set diamonds $default(diamonds)
    set score $default(score)
    set background $default(background)
    set object_current $object_default
    set should_save 0
}
setDefaults

# reset field
proc resetField {} {
    global field_height field_width
    global field

    for {set j 0} {$j < $field_height} {incr j} {
        for {set i 0} {$i < $field_width} {incr i} {
            set field($i,$j) 0
        }
    }
}
resetField


# clear all
proc clearObjects {} {
    resetField
    repaint
    wasEdit
}


# repaint all
proc repaint {} {
    paintBackground
    paintAllObjects
}

# paint background
proc paintBackground {} {
    global image_surface
    global image_background
    global background

    $image_surface copy $image_background($background)
}

# paint all objects
proc paintAllObjects {} {
    global image_surface
    global image_object
    global size_object

    global field_height field_width
    global field

    for {set j 0} {$j < $field_height} {incr j} {
        for {set i 0} {$i < $field_width} {incr i} {
            set x1 [expr $i*$size_object]
            set y1 [expr $j*$size_object]
            set x2 [expr $x1+$size_object]
            set y2 [expr $y1+$size_object]
            set tmp $field($i,$j)
            if {$tmp != 0} {
                $image_surface copy $image_object($tmp) -to $x1 $y1 $x2 $y2
            }
        }
    }
}

# paint object
proc paintObject {x y} {
    global image_object
    global field
    global object_current
    global size_object
    global show_grid
    global image_surface
    global field_height field_width

    set field_x [expr $x/$size_object]
    set field_y [expr $y/$size_object]

    if {$field_x >= 0 && $field_y >= 0 && $field_x < $field_width && $field_y < $field_height && \
        $field($field_x,$field_y) != $object_current} {

        if {$object_current != 0} {
            set x1 [expr $field_x*$size_object]
            set y1 [expr $field_y*$size_object]
            set x2 [expr $x1+$size_object]
            set y2 [expr $y1+$size_object]

            set field($field_x,$field_y) $object_current
            $image_surface copy $image_object($object_current) -to $x1 $y1 $x2 $y2
            wasEdit
        } else {
            deleteObject $x $y
        }
    }
}

# delete object
proc deleteObject {x y} {
    global field
    global size_object
    global image_background
    global image_surface
    global background
    global field_height field_width

    set field_x [expr $x/$size_object]
    set field_y [expr $y/$size_object]

    if {$field_x >= 0 && $field_y >= 0 && $field_x < $field_width && $field_y < $field_height && \
        $field($field_x,$field_y) != 0} {

        set field($field_x,$field_y) 0

        set x1 [expr $field_x*$size_object]
        set y1 [expr $field_y*$size_object]
        set x2 [expr $x1+$size_object]
        set y2 [expr $y1+$size_object]

        $image_surface copy $image_background($background) -from $x1 $y1 $x2 $y2 -to $x1 $y1 $x2 $y2
        wasEdit
    }
}


# about box
proc aboutBox {} {
    tk_messageBox -icon info -type ok -title "About" -message "Level Creator for Bubble\n by Rainer"
}

# error dialog diamonds
proc dialogDiamonds {} {
    tk_messageBox -icon info -type ok -title "Error" -message "Too much diamonds!"
}

# error dialog open
proc dialogOpen {fn} {
    tk_messageBox -icon info -type ok -title "Error" -message [format "Can't open file: %s!" $fn]
}

# error dialog save
proc dialogSave {fn} {
    tk_messageBox -icon info -type ok -title "Error" -message [format "Can't save file: %s!" $fn]
}

# level was not saved
proc dialogDiscard {} {
    set answer [tk_messageBox -icon warning -type yesno -title "Attention" -message "Discard level?"]
    return $answer
}


# set filename
proc setFilename {fn} {
    global filename
    global title_text
    global should_save

    set filename $fn
    wm title . [format "%s%s%s" $title_text ": " [file tail $filename]]
    set should_save 0
}

# reset filename
proc resetFilename {} {
    global filename
    global title_text
    global should_save

    set filename ""
    wm title . $title_text
    set should_save 0
}
resetFilename

# active scales (workaround for scales)
set active 0
proc wasEdit3 {x} {
    global active

    set active 1
}

# scals moved
proc wasEdit2 {x} {
    global active

    if { $active == 1 } {
        wasEdit
    }
}

# level was edited
proc wasEdit {} {
    global filename
    global title_text
    global should_save

    if {$should_save==0} {
        set should_save 1
        wm title . [format "%s%s%s%s" $title_text ": " [file tail $filename] "*"]
    }
}

# new
proc new {} {
    global should_save

    # check for saving
    if {$should_save==1} {
        if {[dialogDiscard]=="no"} {
            return
        }
    }

    setDefaults
    clearObjects
    resetFilename
}

# open
proc openAs {} {
    global filename
    global field_height field_width
    global fishes snakes sharks stars
    global maxfishes diamonds score
    global background
    global field
    global should_save

    # check for saving
    if {$should_save==1} {
        if {[dialogDiscard]=="no"} {
            return
        }
    }

    # file types
    set types {
        {"Level files"     .lev       }
        {"All files"      .*         }
    }

    # get file name
    set fn [tk_getOpenFile -filetypes $types -defaultextension .txt]

    # check filename and save
    if {$fn != ""} {
        openFile $fn
    }
}

# open file
proc openFile {fn} {
    global filename
    global field_height field_width
    global fishes snakes sharks stars
    global maxfishes diamonds score
    global background
    global field
    global version

    # check filename and save
    # open file
    set retval [catch {set infile [open $fn r]}]
    if {$retval == 1} {
        dialogOpen $fn
        return
    }

    # get options
    set i 0
    while {[gets $infile line] != -1 && $i < 9} {
        if {[string index $line 0] != "" && [string index $line 0] != "/"} {
            set input($i) $line
            set i [expr $i+1]
        }
    }

    # set options
    if { [catch {set tmp $input(0)} errorx]} {
        close $infile
        dialogOpen $fn
        return
    }
    if { $tmp != $version} {
        close $infile
        dialogOpen $fn
        return
    }

    set fishes $input(1)
    set snakes $input(2)
    set sharks $input(3)
    set stars $input(4)
    set maxfishes $input(5)
    set diamonds $input(6)
    set score $input(7)
    set background $input(8)

    # get and set field
    set j 0
    while {[gets $infile line] != -1 && $j < $field_height} {
        if {[string index $line 0] != "" && [string index $line 0] != "/"} {
            # scan $line "%s %s %s %s %s %s %s %s" field($i,$j) field($i,$j) field($i,$j) field($i,$j)
            for {set i 0} {$i < $field_width} {incr i} {
                set field($i,$j) [string index $line [expr 2*$i]]
            }

            set j [expr $j+1]
        }
    }
    repaint

    # close file
    close $infile

    # set new filename
    setFilename $fn
}

# save as
proc saveAs {} {
    global filename

    # check diamonds
    if { [checkDiamonds] == 1 } {
        dialogDiamonds
        return
    }

    # default file name
    if {$filename == ""} {
        set tmp_filename "level_test"
    } else {
        set tmp_filename [file tail $filename]
    }

    # get file name
    set fn [tk_getSaveFile -filetypes {{"Text files" .txt} {"Text files" {} TEXT} {"All files" .*}} -initialfile $tmp_filename -defaultextension .txt]

    # check filename and save
    if {$fn != ""} {
        saveFile $fn
    }
}

# check number of diamonds
proc checkDiamonds {} {
    global diamonds
    global field
    global field_height field_width

    set tmp_diamonds 0
    for {set j 0} {$j < $field_height} {incr j} {
        for {set i 0} {$i < $field_width} {incr i} {

            if { $field($i,$j) == 3} {
                set tmp_diamonds [expr $tmp_diamonds+1]
            }
        }
    }

    if { $tmp_diamonds > $diamonds} {
        return 1
    } else {
        return 0
    }
}

# save
proc save {} {
    global filename

    # check diamonds
    if { [checkDiamonds] == 1 } {
        dialogDiamonds
        return
    }

    # check filename and save
    if {$filename == ""} {
        saveAs
    } else {
        saveFile $filename
    }
}

# save file
proc saveFile {fn} {
    global filename
    global fishes snakes sharks stars
    global maxfishes diamonds score
    global background
    global field
    global field_height
    global version

    # open file
    set retval [catch {set outfile [open $fn w]}]
    if {$retval == 1} {
        dialogSave $fn
        return
    }

    # write
    puts $outfile "// bubble level"
    puts $outfile "// created by bedit (the level editor for Bubble)"
    puts $outfile ""
    puts $outfile "// version of this level file (don't edit)"
    puts $outfile $version
    puts $outfile ""
    puts $outfile "// number of fishes (0-99)"
    puts $outfile [format "%s" $fishes]
    puts $outfile ""
    puts $outfile "// number of snakes (0-99)"
    puts $outfile [format "%s" $snakes]
    puts $outfile ""
    puts $outfile "// number of sharks (0-99)"
    puts $outfile [format "%s" $sharks]
    puts $outfile ""
    puts $outfile "// number of stars (0-99)"
    puts $outfile [format "%s" $stars]
    puts $outfile ""
    puts $outfile "// maximum number of fishes at the same time (0-99)"
    puts $outfile [format "%s" $maxfishes]
    puts $outfile ""
    puts $outfile "// number of diamonds (0-99)"
    puts $outfile [format "%s" $diamonds]
    puts $outfile ""
    puts $outfile "// score / time for this level (1000-9999)"
    puts $outfile [format "%s" $score]
    puts $outfile ""
    puts $outfile "// background number (1-50)"
    puts $outfile [format "%s" $background]
    puts $outfile ""
    puts $outfile "// field (0=none, 1=rock, 2=stone, 3=diamond (optional),"
    puts $outfile "//        4=blue ball, 5=pink ball, 6=red dynamite,"
    puts $outfile "//        7=pink dynamite)"
    for {set j 0} {$j < $field_height} {incr j} {
        puts $outfile [format "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s" $field(0,$j) \
            $field(1,$j) $field(2,$j) $field(3,$j) $field(4,$j) $field(5,$j) $field(6,$j) \
            $field(7,$j) $field(8,$j) $field(9,$j) $field(10,$j) $field(11,$j) $field(12,$j) \
            $field(13,$j) $field(14,$j) $field(15,$j)]
    }

    # close file
    close $outfile

    setFilename $fn
}


# select next background
proc nextBackground {} {
    global background to

    if {$background < $to(background)} {
        set background [expr $background + 1]
        repaint
        wasEdit
    }
}

# select prev background
proc prevBackground {} {
    global background from

    if {$background > $from(background)} {
        set background [expr $background - 1]
        repaint
        wasEdit
    }
}

# select next object
proc nextObject {} {
    global object_min object_max
    global object_current

    set object_current [expr $object_current+1]

    if {$object_current > $object_max} {
        set object_current $object_min
    }
}


# show grid
proc showGrid {} {
    global grids
    global show_grid
    global field_height field_width

    for {set j 0} {$j < $field_height} {incr j} {
        for {set i 0} {$i < $field_width} {incr i} {
            if {$show_grid == 0} {
                .field.c itemconfigure $grids($i,$j) -state hidden
            } else {
                .field.c itemconfigure $grids($i,$j) -state normal
            }
        }
    }
}

proc enterField {w} {
    $w itemconfig current -fill red
    #-outline red
}

proc leaveField {w} {
    $w itemconfig current -fill blue
}

# quit
proc quit {} {
    global should_save

    # check for saving
    if {$should_save==1} {
        if {[dialogDiscard]=="no"} {
            return
        }
    }

    # exit
    exit
}


# get command line arguments
if {$argc == 1} {
    openFile [lindex $argv 0]
} elseif {$argc > 1} {
    puts stdout "usage: bedit \[file\]"
    exit
}



