-----------------------------------------------------------------------
-- An example of Actor Prolog program.                               --
-- (c) 2012 IRE RAS Alexei A. Morozov                                --
-----------------------------------------------------------------------

import .. from "morozov/Java3D";
import .. from "morozov/Sound";

class 'Main' (specialized 'Canvas3D'):
--
constant:
--
bounds          : BoundingSphere        = 'BoundingSphere'({});
--
clicked_color   : Appearance
                        = 'Appearance'({
                                material: 'Material'({
                                        emissiveColor: 'Emerald',
                                        lightingEnable: 'yes'
                                        })
                                });
entered_color   : Appearance
                        = 'Appearance'({
                                material: 'Material'({
                                        emissiveColor: 'Lime',
                                        lightingEnable: 'yes'
                                        })
                                });
exited_color    : Appearance
                        = 'Appearance'({
                                material: 'Material'({
                                        emissiveColor: 'Black',
                                        lightingEnable: 'yes'
                                        })
                                });
--
fontName        : FontName              = 'helvetica';
tessellationTolerance
                : TessellationTolerance = 1.0e-2;
--
bold_font       : Font3D
                        = 'Font3D'({
                                fontName,
                                fontSize: 230,
                                fontStyle: ['bold'],
                                extrudePath: 'FontExtrusion'({
                                        depth: 0
                                        }),
                                tessellationTolerance
                                });
normal_font     : Font3D
                        = 'Font3D'({
                                fontName,
                                fontSize: 230,
                                fontStyle: [],
                                extrudePath: 'FontExtrusion'({
                                        depth: 0
                                        }),
                                tessellationTolerance
                                });
--
background_color                        = 'Black';
enable_scene_antialiasing               = 'yes';
--
internal:
--
clip_0          = ('Clip',
                        name="jar:data/phone_button_0.wav");
clip_1          = ('Clip',
                        name="jar:data/phone_button_1.wav");
clip_2          = ('Clip',
                        name="jar:data/phone_button_2.wav");
clip_3          = ('Clip',
                        name="jar:data/phone_button_3.wav");
clip_4          = ('Clip',
                        name="jar:data/phone_button_4.wav");
clip_5          = ('Clip',
                        name="jar:data/phone_button_5.wav");
clip_6          = ('Clip',
                        name="jar:data/phone_button_6.wav");
clip_7          = ('Clip',
                        name="jar:data/phone_button_7.wav");
clip_8          = ('Clip',
                        name="jar:data/phone_button_8.wav");
clip_9          = ('Clip',
                        name="jar:data/phone_button_9.wav");
--
calculator      = ('SimpleCalculator',
                        display=self);
--
con             = ('Console',
                        x= 40,
                        width= 40);
--
constant:
--
character_code_Sign             = 16#B1#;
character_code_Backspace        = 16#2190#;
character_code_Multiply         = 16#D7#;
character_code_Minus            = 16#2212#;
--
[
PREDICATES:
--
imperative:
--
one_button(     Numerical,
                Numerical,
                STRING) = Node          - (i,i,i);
one_button(     Numerical,
                Numerical,
                STRING,
                Text3D_VerticalAlignment,
                Numerical) = Node       - (i,i,i,i,i);
--
display(Numerical,Numerical) = Node             - (i,i);
--
point_light(    Numerical,
                Numerical,
                Angle,
                TimeInterval,
                Color) = Node           - (i,i,i,i,i);
--
update_appearance_and_font
        (NodeLabels,Appearance,Font3D)          - (i,i,i);
update_appearance_and_font_of_node
        (NodeLabel,Appearance,Font3D)           - (i,i,i);
--
update_font(NodeLabels,Font3D)                  - (i,i);
update_font_of_node(NodeLabel,Font3D)           - (i,i);
--
get_sound(NodeLabel,'Clip')                     - (i,o);
get_numbered_sound(Numerical,'Clip')            - (i,o);
--
play_clip('Clip')                               - (i);
--
process_mouse_click(NodeLabel)                  - (i);
show_value(_)                                   - (i);
--
determ:
--
concat(NodeLabel,NodeLabel,NodeLabel)   - (i,o,i)(i,i,o);
--
CLAUSES:
--
goal:-!,
        clip_0 ? open,
        clip_1 ? open,
        clip_2 ? open,
        clip_3 ? open,
        clip_4 ? open,
        clip_5 ? open,
        clip_6 ? open,
        clip_7 ? open,
        clip_8 ? open,
        clip_9 ? open,
        --
        Sign== ?codes_to_string([character_code_Sign]),
        Backspace== ?codes_to_string([character_code_Backspace]),
        Multiply== ?codes_to_string([character_code_Multiply]),
        Minus== ?codes_to_string([character_code_Minus]),
        --
        Brightness== 1.0,
        HalfBrightness== Brightness / 2,
        --
        DeltaX== 450,
        X_U1== DeltaX,
        X_U2== X_U1 + DeltaX,
        X_D1== - (DeltaX),
        X_D2== X_D1 - DeltaX,
        --
        DeltaY== 320,
        Y_U1== DeltaY,
        Y_U2== Y_U1 + 220,
        Y_D1== - (DeltaY),
        Y_D2== Y_D1 - DeltaY,
        --
        show([  'TransformGroup'({
                        allowChildrenWrite: 'yes',
                        transform3D: 'Transform3D'({
                                scale: 0.00059
                                }),
                        branches: [
                                ?display(0,Y_U2),
                                ?one_button(X_D2,Y_D2,"0"),
                                ?one_button(X_D1,Y_D2,Sign),
                                ?one_button(0,Y_D2,",",'ALIGN_TOP',0),
                                ?one_button(X_D2,Y_D1,"1"),
                                ?one_button(X_D1,Y_D1,"2"),
                                ?one_button(0,Y_D1,"3"),
                                ?one_button(X_D2,0,"4"),
                                ?one_button(X_D1,0,"5"),
                                ?one_button(0,0,"6"),
                                ?one_button(X_D2,Y_U1,"7"),
                                ?one_button(X_D1,Y_U1,"8"),
                                ?one_button(0,Y_U1,"9"),
                                ?one_button(X_U1,Y_U1,"/"),
                                ?one_button(X_U1,0,Multiply,'ALIGN_CENTER',-35),
                                ?one_button(X_U1,Y_D1,Minus,'ALIGN_CENTER',-60),
                                ?one_button(X_U1,Y_D2,"+",'ALIGN_CENTER',-27),
                                ?one_button(X_U2,Y_U1,"C"),
                                ?one_button(X_U2,0,Backspace,'ALIGN_TOP',11),
                                ?one_button(X_U2,Y_D1,"%"),
                                ?one_button(X_U2,Y_D2,"=",'ALIGN_TOP',-14)
                                ]
                        }),
                'Background'({
                        color: background_color,
                        applicationBounds: bounds
                        }),
                'AmbientLight'({
                        lightOn: 'yes',
                        color: 'White',
                        influencingBounds: bounds
                        }),
                ?point_light(-0.5,0.5,(?'-'(?pi()) / 4),7300,color3(Brightness,0.0,0.0)),
                ?point_light(0.1,0.5,?'-'(?pi()),15100,color3(0.0,Brightness,0.0)),
                ?point_light(-0.5,0.1,(?pi() / 4),9100,color3(0.0,0.0,Brightness)),
                ?point_light(0.5,0.1,(?pi() / 8),5310,color3(HalfBrightness,HalfBrightness,0.0)),
                ?point_light(-0.1,-0.5,(?'-'(?pi()) / 8),11010,color3(0.0,HalfBrightness,HalfBrightness)),
                ?point_light(-0.5,-0.1,(?'-'(?pi()) / 3),8310,color3(HalfBrightness,0.0,HalfBrightness)),
                'PickCanvas'({
                        handleMouseClicked: 'yes',
                        handleMouseEntered: 'yes',
                        handleMouseExited: 'yes',
                        handleMousePressed: 'yes',
                        handleMouseReleased: 'no',
                        handleMouseDragged: 'no',
                        handleMouseMoved: 'no',
                        isPassive: 'no',
                        period: 150,
                        tolerance: 3,
                        mode: 'GEOMETRY'
                        })
                ]),
        calculator ? display_current_value.
--
one_button(X,Y,Text)
        = ?one_button(X,Y,Text,'ALIGN_CENTER',0).
--
one_button(X,Y,Text,VerticalAlignment,Y0)
        = 'TransformGroup'({
                allowChildrenWrite: 'yes',
                transform3D: 'Transform3D'({
                        translation: [X,Y,0]
                        }),
                branches: [
                        'Sphere'({
                                label: ?cast("NodeLabel",Text),
                                radius: 150,
                                divisions: 300,
                                enableGeometryPicking: 'yes',
                                enableAppearanceModify: 'yes',
                                generateNormals: 'yes',
                                generateNormalsInward: 'yes',
                                appearance: 'Appearance'({
                                        material: 'Material'({
                                                ambientColor: 'Black',
                                                diffuseColor: 'Black',
                                                specularColor: 'White',
                                                emissiveColor: 'Black',
                                                shininess: 25
                                                })
                                        })
                                }),
                        'Shape3D'({
                                label: LetterLabel,
                                allowGeometryRead: 'yes',
                                allowAppearanceWrite: 'yes',
                                geometry: 'Text3D'({
                                        allowFont3DRead: 'yes',
                                        allowFont3DWrite: 'yes',
                                        font3D: normal_font,
                                        string: Text,
                                        position: p(0,Y0,0),
                                        horizontalAlignment: 'ALIGN_CENTER',
                                        verticalAlignment: VerticalAlignment,
                                        path: 'PATH_RIGHT',
                                        characterSpacing: 0.0
                                        }),
                                appearance: exited_color
                                })
                        ]
                }) :-
        LetterLabel== "letter_" + Text.
        --
display(X,Y)
        = 'TransformGroup'({
                allowChildrenWrite: 'yes',
                transform3D: 'Transform3D'({
                        translation: [X,Y,0]
                        }),
                branches: [
                        'Shape3D'({
                                label: "DISPLAY",
                                allowGeometryRead: 'yes',
                                allowAppearanceWrite: 'yes',
                                geometry: 'Text3D'({
                                        allowFont3DRead: 'yes',
                                        allowFont3DWrite: 'yes',
                                        allowStringRead: 'yes',
                                        allowStringWrite: 'yes',
                                        font3D: 'Font3D'({
                                                fontName,
                                                fontSize: 270,
                                                fontStyle: [],
                                                extrudePath: 'FontExtrusion'({
                                                        depth: 0
                                                        }),
                                                tessellationTolerance
                                                }),
                                        string: "",
                                        position: p(0,0,0),
                                        horizontalAlignment: 'ALIGN_CENTER',
                                        verticalAlignment: 'ALIGN_CENTER',
                                        path: 'PATH_RIGHT',
                                        characterSpacing: 0.0
                                        }),
                                appearance: exited_color
                                })
                        ]
                }).
--
point_light(X0,Y0,RotZ,Increasing,C)
        = 'TransformGroup'({
                allowTransformRead: 'yes',
                allowTransformWrite: 'yes',
                branches: [
                        'TransformGroup'({
                                transform3D: 'Transform3D'({
                                        translation: [X0,Y0,0.5]
                                        }),
                                branches: [
                                        'PointLight'({
                                                color: C,
                                                influencingBounds: Bounds
                                                })
                                        ]
                                }),
                        'RotationInterpolator'({
                                alpha: 'Alpha3D'({
                                        increasingAlphaDuration: Increasing
                                        }),
                                transformAxis: 'Transform3D'({
                                        rotZ: RotZ
                                        }),
                                schedulingBounds: Bounds
                                })
                        ]
                })
        :-
        Bounds== 'BoundingSphere'({radius: 10}).
--
mouse_clicked([NodeLabel|_]):-!,
        update_font_of_node(NodeLabel,normal_font).
--
mouse_entered([NodeLabel|_]):-!,
        update_appearance_and_font_of_node(
                NodeLabel,entered_color,normal_font).
--
mouse_exited([NodeLabel|_]):-!,
        update_appearance_and_font_of_node(
                NodeLabel,exited_color,normal_font).
--
mouse_pressed([NodeLabel|_]):-!,
        get_sound(NodeLabel,Clip),
        play_clip(Clip),
        update_appearance_and_font_of_node(
                NodeLabel,clicked_color,bold_font),
        process_mouse_click(NodeLabel).
--
mouse_released(_):-!.
--
mouse_dragged(_):-!.
--
mouse_moved(_):-!.
--
update_appearance_and_font([NL|Rest],Appearance,Font):-!,
        update_appearance_and_font_of_node(NL,Appearance,Font),
        update_appearance_and_font(Rest,Appearance,Font).
update_appearance_and_font([],_,_).
--
update_appearance_and_font_of_node("DISPLAY",_,_):-!.
update_appearance_and_font_of_node(NodeLabel,Appearance,Font):-
        concat("letter_",_,NodeLabel),!,
        set_appearance(NodeLabel,Appearance),
        set_font3d(NodeLabel,Font).
update_appearance_and_font_of_node(NodeLabel1,Appearance,Font):-
        concat("letter_",NodeLabel1,NodeLabel2),!,
        set_appearance(NodeLabel2,Appearance),
        set_font3d(NodeLabel2,Font).
update_appearance_and_font_of_node(_,_,_).
--
update_font([NL|Rest],Font):-!,
        update_font_of_node(NL,Font),
        update_font(Rest,Font).
update_font([],_).
--
update_font_of_node("DISPLAY",_):-!.
update_font_of_node(NodeLabel,Font):-
        concat("letter_",_,NodeLabel),!,
        set_font3d(NodeLabel,Font).
update_font_of_node(NodeLabel1,Font):-
        concat("letter_",NodeLabel1,NodeLabel2),!,
        set_font3d(NodeLabel2,Font).
update_font_of_node(_,_).
--
set_font3d(_,_):-!.
--
get_sound(NodeLabel,Clip):-
        N== ?convert_to_integer(NodeLabel),!,
        get_numbered_sound(N,Clip).
get_sound("/",Clip):-!,
        get_numbered_sound(1,Clip).
get_sound("C",Clip):-!,
        get_numbered_sound(2,Clip).
get_sound(Label,Clip):-
        Label == ?codes_to_string([character_code_Multiply]),!,
        get_numbered_sound(3,Clip).
get_sound(Label,Clip):-
        Label == ?codes_to_string([character_code_Backspace]),!,
        get_numbered_sound(4,Clip).
get_sound(Label,Clip):-
        Label == ?codes_to_string([character_code_Minus]),!,
        get_numbered_sound(5,Clip).
get_sound("%",Clip):-!,
        get_numbered_sound(6,Clip).
get_sound(",",Clip):-!,
        get_numbered_sound(7,Clip).
get_sound(Label,Clip):-
        Label == ?codes_to_string([character_code_Sign]),!,
        get_numbered_sound(8,Clip).
get_sound("+",Clip):-!,
        get_numbered_sound(9,Clip).
get_sound("=",Clip):-!,
        get_numbered_sound(0,Clip).
get_sound(_,Clip):-
        get_numbered_sound(0,Clip).
--
get_numbered_sound(0,clip_0):-!.
get_numbered_sound(1,clip_1):-!.
get_numbered_sound(2,clip_2):-!.
get_numbered_sound(3,clip_3):-!.
get_numbered_sound(4,clip_4):-!.
get_numbered_sound(5,clip_5):-!.
get_numbered_sound(6,clip_6):-!.
get_numbered_sound(7,clip_7):-!.
get_numbered_sound(8,clip_8):-!.
get_numbered_sound(9,clip_9):-!.
get_numbered_sound(_,clip_0).
--
play_clip(Clip):-
        Clip ? stop,
        Clip ? set_frame_position(0),
        Clip ? start,!.
play_clip(_).
--
process_mouse_click(Label):-
        N== ?convert_to_integer(Label),!,
        calculator ? enter_digit(N).
process_mouse_click(Label):-
        Label == ?codes_to_string([character_code_Sign]),!,
        calculator ? change_sign.
process_mouse_click(","):-!,
        calculator ? begin_fractional_part.
process_mouse_click("C"):-!,
        calculator ? reset.
process_mouse_click(Label):-
        Label == ?codes_to_string([character_code_Backspace]),!,
        calculator ? backspace.
process_mouse_click("+"):-!,
        calculator ? operation('plus').
process_mouse_click(Label):-
        Label == ?codes_to_string([character_code_Minus]),!,
        calculator ? operation('minus').
process_mouse_click(Label):-
        Label == ?codes_to_string([character_code_Multiply]),!,
        calculator ? operation('multiply').
process_mouse_click("/"):-!,
        calculator ? operation('divide').
process_mouse_click("="):-!,
        calculator ? enter.
process_mouse_click("%"):-!,
        calculator ? percent.
process_mouse_click(_).
--
show_value(V):-
        set_string("DISPLAY",V).
]

class 'SimpleCalculator' (specialized 'Database'):
--
internal:
--
display         : 'Main';
--
text_operations = ('Text');
--
con             = ('Console');
--
[
DOMAINS:
--
Target          = sign(INTEGER);
                  integer_part(INTEGER);
                  'has_fractional_part';
                  fractional_part(INTEGER,INTEGER);
                  first_argument(
                        INTEGER,INTEGER,INTEGER,INTEGER);
                  second_argument(
                        INTEGER,INTEGER,INTEGER,INTEGER);
                  current_operation(Operation);
                  'first_argument_is_displayed';
                  'result_is_displayed'.
Operation       = 'plus'; 'minus'; 'multiply'; 'divide'.
--
PREDICATES:
--
imperative:
--
reset;
prepare_display_if_necessary;
clear_display;
--
enter_digit(INTEGER)                            - (i);
percent;
change_sign;
begin_fractional_part;
backspace;
--
operation(Operation)                            - (i);
enter;
--
remember_second_argument;
--
implement_operation(
        INTEGER /* Sign */,
        INTEGER /* IntegerPart */,
        INTEGER /* FractionalPart */,
        INTEGER /* Counter */,
        Operation)                      - (i,i,i,i,i);
implement_operation(
        INTEGER /* Sign */,
        INTEGER /* IntegerPart */,
        INTEGER /* FractionalPart */,
        INTEGER /* Counter */,
        INTEGER /* Sign */,
        INTEGER /* IntegerPart */,
        INTEGER /* FractionalPart */,
        INTEGER /* Counter */,
        Operation)                      - (i,i,i,i,i,i,i,i,i);
implement_operation(
        Numerical,
        Numerical,
        Operation) = Numerical          - (i,i,i);
--
determ:
--
is_zero(Numerical)                              - (i);
--
imperative:
--
assemble_number(
        INTEGER /* Sign */,
        INTEGER /* IntegerPart */,
        INTEGER /* FractionalPart */,
        INTEGER /* Counter */) = Numerical      - (i,i,i,i);
--
dismantle_number(
        Numerical,
        INTEGER /* Sign */,
        INTEGER /* IntegerPart */,
        INTEGER /* FractionalPart */,
        INTEGER /* Counter */)          - (i,o,o,o,o);
dismantle_number(
        Numerical,
        INTEGER /* IntegerPart */,
        INTEGER /* FractionalPart */,
        INTEGER /* Counter */)          - (i,o,o,o);
--
determ:
--
search_dot(STRING) = INTEGER                    - (i);
--
imperative:
--
count_nonzero_digits
        (STRING,STRING,INTEGER,INTEGER)         - (i,o,i,o);
--
determ:
--
are_zeros(STRING)                               - (i);
--
imperative:
--
convert_number(INTEGER,STRING) = INTEGER        - (i,i);
--
update_current_value(
        INTEGER /* Sign */,
        INTEGER /* IntegerPart */,
        INTEGER /* FractionalPart */,
        INTEGER /* Counter */)          - (i,i,i,i);
--
display_current_value;
display_current_value(INTEGER)                  - (i);
--
get_current_value(
        INTEGER /* Sign */,
        INTEGER /* IntegerPart */,
        INTEGER /* FractionalPart */,
        INTEGER /* Counter */)          - (o,o,o,o);
--
get_sign(INTEGER)                               - (o);
sign_to_text(INTEGER,STRING)                    - (i,o);
--
determ:
--
get_fractional_part_or_Fail(INTEGER,INTEGER)    - (o,o);
--
imperative:
--
get_integer_part(INTEGER)                       - (o);
--
'+'(Numerical,Numerical) = Numerical            - (i,i);
'-'(Numerical,Numerical) = Numerical            - (i,i);
'-'(Numerical) = Numerical                      - (i);
'*'(Numerical,Numerical) = Numerical            - (i,i);
'/'(Numerical,Numerical) = Numerical            - (i,i);
--
CLAUSES:
--
reset:-
        retract_all,
        display_current_value.
--
prepare_display_if_necessary:-
        find('result_is_displayed'),!,
        retract_all('result_is_displayed'),
        clear_display.
prepare_display_if_necessary:-
        find('first_argument_is_displayed'),!,
        retract_all('first_argument_is_displayed'),
        clear_display.
prepare_display_if_necessary.
--
clear_display:-
        retract_all('has_fractional_part'),
        retract_all(sign(_)),
        retract_all(integer_part(_)),
        retract_all(fractional_part(_,_)).
--
enter_digit(_):-
        prepare_display_if_necessary,
        fail.
enter_digit(Digit):-
        Item== ?match(fractional_part(_,_)),
        Item == fractional_part(N1,C1),!,
        N2== N1 * 10 + Digit,
        C2== C1 + 1,
        retract_all(fractional_part(_,_)),
        insert(fractional_part(N2,C2)),
        display_current_value.
enter_digit(N2):-
        find('has_fractional_part'),!,
        insert(fractional_part(N2,1)),
        display_current_value.
enter_digit(Digit):-
        Item== ?match(integer_part(_)),
        Item == integer_part(N1),!,
        N2== N1 * 10 + Digit,
        retract_all(integer_part(_)),
        insert(integer_part(N2)),
        display_current_value.
enter_digit(N2):-
        insert(integer_part(N2)),
        display_current_value.
--
percent:-
        Item1== ?match(first_argument(_,_,_,_)),
        Item1 == first_argument(
                Sign1,IntegerPart1,FractionalPart1,Counter1),!,
        get_current_value(
                Sign2,IntegerPart2,FractionalPart2,Counter2),
        V1== ?assemble_number(
                Sign1,IntegerPart1,FractionalPart1,Counter1),
        V2== ?assemble_number(
                Sign2,IntegerPart2,FractionalPart2,Counter2),
        V3== V1 / 100 * V2,
        dismantle_number(
                V3,Sign3,IntegerPart3,FractionalPart3,Counter3),
        update_current_value(
                Sign3,IntegerPart3,FractionalPart3,Counter3),
        display_current_value.
percent.
--
change_sign:-
        prepare_display_if_necessary,
        fail.
change_sign:-
        Item== ?match(sign(_)),
        Item == sign(N1),!,
        N2== - (N1),
        retract_all(sign(_)),
        insert(sign(N2)),
        display_current_value(N2).
change_sign:-
        N2== -1,
        insert(sign(N2)),
        display_current_value(N2).
--
begin_fractional_part:-
        prepare_display_if_necessary,
        fail.
begin_fractional_part:-
        find('has_fractional_part'),!.
begin_fractional_part:-
        insert('has_fractional_part'),
        display_current_value.
--
backspace:-
        prepare_display_if_necessary,
        fail.
backspace:-
        Item== ?match(fractional_part(_,_)),
        Item == fractional_part(_,1),!,
        retract_all(fractional_part(_,_)),
        display_current_value.
backspace:-
        Item== ?match(fractional_part(_,_)),
        Item == fractional_part(N1,C1),!,
        N2== ?div(N1,10),
        C2== C1 - 1,
        retract_all(fractional_part(_,_)),
        insert(fractional_part(N2,C2)),
        display_current_value.
backspace:-
        find('has_fractional_part'),!,
        retract_all('has_fractional_part'),
        display_current_value.
backspace:-
        Item== ?match(integer_part(_)),
        Item == integer_part(N1),!,
        N2== ?div(N1,10),
        retract_all(integer_part(_)),
        insert(integer_part(N2)),
        display_current_value.
backspace.
--
operation(Operation):-
        find('result_is_displayed'),!,
        retract_all(current_operation(_)),
        insert(current_operation(Operation)).
operation(Operation):-
        find('first_argument_is_displayed'),!,
        retract_all(current_operation(_)),
        insert(current_operation(Operation)).
operation(Operation):-
        get_current_value(
                Sign,IntegerPart,FractionalPart,Counter),
        retract_all(first_argument(_,_,_,_)),
        retract_all(second_argument(_,_,_,_)),
        retract_all(current_operation(_)),
        retract_all('first_argument_is_displayed'),
        insert(first_argument(
                Sign,IntegerPart,
                FractionalPart,Counter)),
        insert(current_operation(Operation)),
        insert('first_argument_is_displayed').
--
enter:-
        find('result_is_displayed'),
        Item1== ?match(first_argument(_,_,_,_)),
        Item2== ?match(current_operation(_)),
        Item1 == first_argument(
                Sign,IntegerPart,FractionalPart,Counter),
        Item2 == current_operation(Operation),!,
        implement_operation(
                Sign,IntegerPart,FractionalPart,Counter,
                Operation).
enter:-
        remember_second_argument,
        Item1== ?match(first_argument(_,_,_,_)),
        Item2== ?match(current_operation(_)),
        Item1 == first_argument(
                Sign,IntegerPart,FractionalPart,Counter),
        Item2 == current_operation(Operation),!,
        implement_operation(
                Sign,IntegerPart,FractionalPart,Counter,
                Operation).
enter.
--
remember_second_argument:-
        get_current_value(
                Sign,IntegerPart,FractionalPart,Counter),
        retract_all(second_argument(_,_,_,_)),
        insert(second_argument(
                Sign,IntegerPart,
                FractionalPart,Counter)).
--
implement_operation(
                Sign1,IntegerPart1,FractionalPart1,Counter1,
                Operation):-
        Item1== ?match(second_argument(_,_,_,_)),
        Item1 == second_argument(
                Sign2,IntegerPart2,FractionalPart2,Counter2),!,
        implement_operation(
                Sign1,IntegerPart1,FractionalPart1,Counter1,
                Sign2,IntegerPart2,FractionalPart2,Counter2,
                Operation).
implement_operation(_,_,_,_,_):-
        break('implement_operation').
--
implement_operation(
                Sign1,IntegerPart1,FractionalPart1,Counter1,
                Sign2,IntegerPart2,FractionalPart2,Counter2,
                Operation):-
        V1== ?assemble_number(
                Sign1,IntegerPart1,FractionalPart1,Counter1),
        V2== ?assemble_number(
                Sign2,IntegerPart2,FractionalPart2,Counter2),
        V3== ?implement_operation(V1,V2,Operation),
        dismantle_number(
                V3,Sign3,IntegerPart3,FractionalPart3,Counter3),
        retract_all(first_argument(_,_,_,_)),
        insert(first_argument(
                Sign3,IntegerPart3,
                FractionalPart3,Counter3)),
        update_current_value(
                Sign3,IntegerPart3,FractionalPart3,Counter3),
        insert('result_is_displayed'),
        display_current_value.
--
implement_operation(V1,V2,'plus') = V1 + V2 :-!.
implement_operation(V1,V2,'minus') = V1 - V2 :-!.
implement_operation(V1,V2,'multiply') = V1 * V2 :-!.
implement_operation(V1,V2,'divide') = V1 :-
        is_zero(V2),!,
        con ? error("Division by zero error!").
implement_operation(V1,V2,'divide') = V1 / V2.
--
is_zero(0):-!.
is_zero(0.0).
--
assemble_number(Sign,IP,0,_) = Value
        :-!,
        Value== Sign * IP.
assemble_number(Sign,IP,FP,Counter) = Value
        :-
        Format== text_operations?format("%%s%%d.%%0%dd",Counter),
        sign_to_text(Sign,ST),
        SignedValue== text_operations?format(Format,ST,IP,FP),
        Value== ?convert_to_real(SignedValue),!.
assemble_number(_,_,_,_) = _
        :-
        break('assemble_number').
--
dismantle_number(V1,-1,IP,FP,Counter):-
        V1 < 0,!,
        V2== -(V1),
        dismantle_number(V2,IP,FP,Counter).
dismantle_number(V,1,IP,FP,Counter):-
        dismantle_number(V,IP,FP,Counter).
--
dismantle_number(V1,V2,0,0):-
        V2== ?val("INTEGER",V1),!.
dismantle_number(V,IP,FP,Counter):-
        -- Text== text_operations?format("%1.15f",V),
        Text== text_operations?format("%1.14f",V),
        P1== ?search_dot(Text),
        P2== P1 - 1,
        text_operations?split(P2,Text,Front,Rest1),
        text_operations?split(1,Rest1,_,Rest2),
        IP== ?convert_to_integer(Front),!,
        count_nonzero_digits(Rest2,Rest3,0,Counter),
        FP== ?convert_number(Counter,Rest3).
dismantle_number(_,_,_,_):-
        break('dismantle_number').
--
search_dot(Text) = P :-
        P== text_operations?search(Text,"."),!.
search_dot(Text) = P :-
        P== text_operations?search(Text,","),!.
--
count_nonzero_digits(S1,"",Counter,Counter):-
        are_zeros(S1),!.
count_nonzero_digits(S1,S4,C1,C2):-
        text_operations?split(1,S1,Digit,S2),!,
        count_nonzero_digits(S2,S3,C1+1,C2),
        text_operations?concat(Digit,S3,S4).
count_nonzero_digits(_,"",Counter,Counter).
--
are_zeros(S1):-
        text_operations?concat("0",S2,S1),!,
        are_zeros(S2).
are_zeros("").
--
convert_number(0,_) = 0 :- !.
convert_number(_,Text) = N :-
        N== ?convert_to_integer(Text),!.
convert_number(_,_) = _ :-
        break('convert_number_if_necessary').
--
update_current_value(_,_,_,_):-
        clear_display,
        fail.
update_current_value(Sign,IP,0,_):-!,
        insert(sign(Sign)),
        insert(integer_part(IP)).
update_current_value(Sign,IP,FP,Counter):-
        insert('has_fractional_part'),
        insert(sign(Sign)),
        insert(integer_part(IP)),
        insert(fractional_part(FP,Counter)).
--
display_current_value:-
        get_sign(Sign),
        display_current_value(Sign).
--
display_current_value(Sign):-
        get_fractional_part_or_Fail(FractionalPart,Counter),!,
        sign_to_text(Sign,ST),
        get_integer_part(IntegerPart),
        Format== text_operations?format("%%s%%d,%%0%dd",Counter),
        SignedValue==
                text_operations?format(
                        Format,ST,IntegerPart,FractionalPart),
        display ? show_value(SignedValue).
display_current_value(Sign):-
        find('has_fractional_part'),!,
        sign_to_text(Sign,ST),
        get_integer_part(IntegerPart),
        display ? show_value(
                text_operations?format("%s%d,",ST,IntegerPart)).
display_current_value(Sign):-
        sign_to_text(Sign,ST),
        get_integer_part(IntegerPart),
        display ? show_value(
                text_operations?format("%s%d",ST,IntegerPart)).
--
get_current_value(Sign,IntegerPart,FractionalPart,Counter):-
        get_fractional_part_or_Fail(FractionalPart,Counter),!,
        get_sign(Sign),
        get_integer_part(IntegerPart).
get_current_value(Sign,IntegerPart,0,0):-
        get_sign(Sign),
        get_integer_part(IntegerPart).
--
get_sign(Sign):-
        Item== ?match(sign(_)),
        Item == sign(Sign),!.
get_sign(1).
--
sign_to_text(-1,"-"):-!.
sign_to_text(_,"").
--
get_fractional_part_or_Fail(N,Counter):-
        Item== ?match(fractional_part(_,_)),
        Item == fractional_part(N,Counter),!.
--
get_integer_part(N):-
        Item== ?match(integer_part(_)),
        Item == integer_part(N),!.
get_integer_part(0).
]