// completely overengineered theme, didn't like anything around the block.
// - cab404

state = "normal";

// ============ Utils
// now we are playing with power (prototypes, yay!)

Object.set_image = fun(image) {
    this.sprite.SetImage(image);
    this.w = image.GetWidth();
    this.h = image.GetHeight();
};

Object.put = fun(x,y) {
    this.x = x;
    this.y = y;
    this.sprite.SetPosition(x, y);
};

Object.below = fun(other, margin) {
    if (margin == null) margin = 0;
    this.y =other.y + other.h + margin;
    this.sprite.SetY(this.y);
};

Object.align_left = fun(other, margin) {
    if (margin == null) margin = 0;
    this.x = other.x + margin;
    this.sprite.SetX(this.x);
};

Object |= fun(image) {
    object = [] | global.Object;
    object.sprite = Sprite(image);
    object.w = image.GetWidth();
    object.h = image.GetHeight();
    object.put(0, 0);
    return object;
};

// and then let's make an object manager!
objstore.store = [];
objstore.mark = 0;
objstore.add = fun (p) {
    for (i = 0; i <= this.mark+1; i++) {
        if (!this.store[i]) {
            this.store[i] = p;
            this.mark = Math.Max(this.mark, i);
            break;
        }
    }
};
objstore.update = fun() {
    for (i = 0; i < this.mark+1; i++) {
        if (this.store[i] && !this.store[i].dead) {
            this.store[i].update();
        }
    }
};

// basic generators
fun whitetext(text, size) {
    return Image.Text(text, 0.7,0.1,0.1,1,"monospace " + size);
}
emptyimage = Image.Text("");

// An object counter
objcounter = Object(emptyimage);
objcounter.put(0,0);
objcounter.update = fun() {
    if (this.curcount != objstore.mark) {
        this.curcount = objstore.mark;
        this.set_image(Image.Text(objstore.mark,0.2,0.2,0.2));
    }
};

objstore.add(objcounter);

// ========== Animated logo
NUMBER_OF_FRAMES = 60;

logo = Object(Image("0.png"));
for (i = 0; i < NUMBER_OF_FRAMES; i++)  { logo.frames[i] = Image( i + ".png"); }
logo.put(20, 20);
logo.frame = 0;
logo.update = fun () {
    this.set_image(global.logo.frames[global.logo.frame]);
    this.frame += 1;
    this.frame %= NUMBER_OF_FRAMES;
};
objstore.add(logo);

fun labeltext() {
    mode = Plymouth.GetMode();
    if (mode == "boot") return "loading NixOS...";
    if (mode == "shutdown") return "shutting down...";
    if (mode == "reboot") return "reboot initiated...";
    if (mode == "updates") return "system update in progress...";
    if (mode == "system-upgrade") return "applying upgrades...";
    if (mode == "firmware-upgrade") return "updating firmware...";
    if (mode == "unknown") return "??? [REDACTED] in [DATA EXPUNGED] ???";
}

label = Object(whitetext(labeltext(), 20));
label.below(logo);
label.align_left(logo);

// ========== Question callback

// Jump on each entered character this many pixels
Q_JUMP=5.0;
q_offset = 0.0;

fun update_quesion(q, a) {
    if (global.state == "input") {
        q_offset = Q_JUMP;
    }
    global.state = "input";

    global.question.prompt = Object(whitetext(q, 10));
    global.question.prompt.below(global.label, 4);
    global.question.prompt.align_left(global.label);
   
    global.question.input = Object(whitetext(a, 10));
    global.question.input.below(global.question.prompt, 4);
    global.question.input.align_left(global.question.prompt);

}

local_q_updater.update = fun(){
    global.q_offset /= 1.2;
    global.question.input.below(global.question.prompt, q_offset);
};
objstore.add(local_q_updater);

fun question_callback(prompt, entry) {
    update_quesion(prompt, entry);
}

fun password_callback(prompt, bullet_count) {
    local.q = "> ";
    for (i = 0; i < bullet_count; i++) local.q += "*";
    update_quesion(prompt, local.q);
}


# Set background color
Window.SetBackgroundTopColor (1, 1, 1);
Window.SetBackgroundBottomColor (1, 1, 1);

Plymouth.SetDisplayQuestionFunction(question_callback);
Plymouth.SetDisplayPasswordFunction(password_callback);

// ========== Message

fun message_callback(text) {
    message = Object(whitetext(text, 12));
    message.below(label, 4);
    message.align_left(label,4);
}

fun hide_message_callback(text) {
    message.set_image(emptyimage);
}

Plymouth.SetMessageFunction(message_callback);

// Maintenance
fun to_normal() {
    global.state = "normal";
    global.question = null;
    global.message = null;
}

Plymouth.SetDisplayNormalFunction(to_normal);

fun refresh_loop() {
    objstore.update();
}  

Plymouth.SetRefreshFunction(refresh_loop);
