#pragma version =0.4.6;
#pragma allow-post-modification;
#pragma compute-asm-ltr;

;; test-simple.tact_TestSimple.headers.fc
;;
;; Header files for TestSimple
;; NOTE: declarations are sorted for optimal order
;;

;; $TestSimple$_store
builder $TestSimple$_store(builder build_0, (int) v) inline;

;; $TestSimple$_load
(slice, ((int))) $TestSimple$_load(slice sc_0) inline;

;; $TestSimple$_contract_init
(int) $TestSimple$_contract_init() impure inline;

;; $TestSimple$_contract_load
(int) $TestSimple$_contract_load() impure inline;

;; $TestSimple$_contract_store
() $TestSimple$_contract_store((int) v) impure inline;

;; $TestSimple$_fun_counter
((int), int) $TestSimple$_fun_counter((int) $self) impure inline_ref;


;; test-simple.tact_TestSimple.stdlib.fc
global (int, slice, int, slice) __tact_context;
global slice __tact_context_sender;
global cell __tact_child_contract_codes;
global int __tact_randomized;

;; test-simple.tact_TestSimple.storage.fc
;;
;; Type: TestSimple
;; TLB: _ counter:uint32 = TestSimple
;;

builder $TestSimple$_store(builder build_0, (int) v) inline {
    var (v'counter) = v;
    build_0 = build_0.store_uint(v'counter, 32);
    return build_0;
}

(slice, ((int))) $TestSimple$_load(slice sc_0) inline {
    var v'counter = sc_0~load_uint(32);
    return (sc_0, (v'counter));
}

(int) $TestSimple$_contract_load() impure inline {
    slice $sc = get_data().begin_parse();
    int $loaded = $sc~load_int(1);
    if ($loaded) {
        return $sc~$TestSimple$_load();
    }
    else {
        return $TestSimple$_contract_init();
    }
}

() $TestSimple$_contract_store((int) v) impure inline {
    builder b = begin_cell();
    b = b.store_int(true, 1);
    b = $TestSimple$_store(b, v);
    set_data(b.end_cell());
}

;;
;; Contract TestSimple functions
;;

(int) $TestSimple$_contract_init() impure inline {
    var (($self'counter)) = (null());
    $self'counter = 0;
    return ($self'counter);
}

((int), int) $TestSimple$_fun_counter((int) $self) impure inline_ref {
    var (($self'counter)) = $self;
    var $fresh$ret_0 = $self'counter;
    return (($self'counter), $fresh$ret_0);
}

;;
;; Get methods of a Contract TestSimple
;;

_ %counter() method_id(104984) {
    var self = $TestSimple$_contract_load();
    var res = self~$TestSimple$_fun_counter();
    return res;
}

;;
;; Routing of a Contract TestSimple
;;

;; message opcode reader utility: only binary receivers
;; Returns 32 bit message opcode, otherwise throws the "Invalid incoming message" exit code
(slice, int) ~load_opcode_internal(slice s) asm( -> 1 0) "32 LDUQ 130 THROWIFNOT";

() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
    
    ;; Context
    var cs = in_msg_cell.begin_parse();
    cs~skip_bits(2);
    var msg_bounceable = cs~load_int(1);
    var msg_bounced = cs~load_int(1);
    slice msg_sender_addr = cs~load_msg_addr();
    __tact_context = (msg_bounceable, msg_sender_addr, msg_value, cs);
    __tact_context_sender = msg_sender_addr;
    
    ;; Load contract data
    var ($self'counter) = $TestSimple$_contract_load();
    
    ;; Handle bounced messages
    if (msg_bounced) { return (); }
    var op = in_msg~load_opcode_internal();
    ;; Receive SimpleMsg message
    if (op == 0x1) {
        var $msg'value = in_msg~load_uint(32);
        $self'counter = $self'counter + $msg'value;
        $TestSimple$_contract_store(($self'counter));
        return ();
    }
    
    ;; Throw if not handled
    throw(130);
}


() __tact_selector_hack_asm() impure asm """
@atend @ 1 {
        execute current@ context@ current!
        {
            // The core idea of this function is to save gas by avoiding unnecessary dict jump, when recv_internal/recv_external is called
            // We want to extract recv_internal/recv_external from the dict and select needed function
            // not by jumping to the needed function by it's index, but by using usual IF statements.

            }END> b> // Close previous builder, now we have a cell of previous code on top of the stack

            <{ // Start of the new code builder
                SETCP0
                // Swap the new code builder with the previous code, now we have previous code on top of the stack
                swap
                // Transform cell to slice and load first ref from the previous code, now we have the dict on top of the stack
                <s ref@

                // Extract the recv_internal from the dict
                dup 0 swap @procdictkeylen idict@ { "internal shortcut error" abort } ifnot
                swap

                // Delete the recv_internal from the dict
                0 swap @procdictkeylen idict- drop
                // Delete the recv_external from the dict (it's okay if it's not there)
                -1 swap @procdictkeylen idict- drop
                // Delete the __tact_selector_hack from the dict
                65535 swap @procdictkeylen idict- drop

                // Bring the code builder from the bottom of the stack
                // because if recv_external extraction is optional, and the number of elements on the stack is not fixed
                depth 1- roll
                // Swap with the dict from which we extracted recv_internal and (maybe) recv_external
                swap

                // Check if the dict is empty
                dup null?
                // Store a copy of this flag in the bottom of the stack
                dup depth 1- -roll
                {
                    // If the dict is empty, just drop it (it will be null if it's empty)
                    drop
                }
                {
                    // If the dict is not empty, prepare continuation to be stored in c3
                    <{
                        // Save this dict as first ref in this continuation, it will be pushed in runtime by DICTPUSHCONST
                        swap @procdictkeylen DICTPUSHCONST
                        // Jump to the needed function by it's index
                        DICTIGETJMPZ
                        // If such key is not found, throw 11 along with the key as an argument
                        11 THROWARG
                    }> PUSHCONT
                    // Store the continuation in c3
                    c3 POP
                } cond

                // Function id is on top of the (runtime) stack
                DUP IFNOTJMP:<{
                    // place recv_internal here
                    DROP swap @addop
                }>

                // Bring back the flag, indicating if the dict is empty or not from the bottom of the stack
                depth 1- roll
                {
                    // If the dict is empty, throw 11
                    11 THROWARG
                }
                {
                    // If the dict is not empty, jump to continuation from c3
                    c3 PUSH JMPX
                } cond
            }> b>
        } : }END>c
        current@ context! current!
    } does @atend !
""";

() __tact_selector_hack() method_id(65535) {
    return __tact_selector_hack_asm();
}