#modules of kivymd
from kivymd.app import MDApp
from kivymd.uix.behaviors import HoverBehavior
from kivymd.uix.menu import MDDropdownMenu
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton, MDFillRoundFlatButton, MDIconButton
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel

#modules of kivy
from kivy.core.window import Window
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager, NoTransition
from kivy.uix.button import Button
from kivy.graphics import Color , RoundedRectangle
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.animation import Animation
from kivy.config import Config

#other modules
import os

#ScreenManger
sm = ScreenManager(transition = NoTransition())

#window fix size
Window.size = (630,450)
#winodw min size
Window.minimum_width = 630
Window.minimum_height = 450

#connected to desgin file
Builder.load_file("desgin.kv")

#main variable
title_note_v = [0]
find_text_note = [0]
replace_text_note = [0]

#hover button
class But(Button, HoverBehavior):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.background_color = (0,0,0,0)
        self.size_hint = None,None
        self.size = (80,32)
        self.pos_hint = {'center_y': 0.5}

    def on_enter(self):

        with self.canvas.before:
            Color(0,0,0,0.6)
            RoundedRectangle(size=(80,32), pos= self.pos, radius=(15,15))

    def on_leave(self):

        self.canvas.before.clear()

#save button
class Save_but(Button, HoverBehavior):
    pass

#dialog of about note
class About_Note_Con(BoxLayout):
    pass

#dialog of short cut
class Short_Cut_Con(ScrollView):
    pass

#dialog of title change
class Title_Con(BoxLayout):

    def text_title(self, text):
        title_note_v[0] = text

# dialog of replace word
class Replace_Con(BoxLayout):

    def find_text(self, text):
        find_text_note[0] = text

    def relplce_text(self, text):
        replace_text_note[0] = text

#Screen
class Main(Screen):

    dialog_title = None
    dialog_new_file = None
    dialog_exit_note = None
    dialog_replace_word = None
    dialog_emoji = None
    dialog_short_cut = None
    dialog_about_note = None
    dialog_save_file = None
    dialog_new_file_save =None
    dialog_new_file_dont_save = None
    dialog_exit_note_file = None

    def __init__(self, **kwargs):
        super(Main, self).__init__(**kwargs)
        os.chdir("D:\\sweety\\Git_learn\\project\\gui_project\\file_manager")

        #variabe of class main
        self.text_note = ''
        self.title_note = ''
        self.emoji_task = False

        #writer board
        self.board = self.ids.note_input
        self.board_text_color = (0/255, 128/255, 0/255,1)
        self.board_text_name = "Comic"
        self.board_zoom = 20

        #create drawn
        set_drawn = self.ids.setting_drawn
        set_drawn.pos = (Window.size[0],0)

    #---------------------------save-button------------------------#

    # if wirte in note ,then color of save button is change
    def color_save_btn(self, text_btn):

        self.text_note = text_btn

        with open(self.title_note, "r") as file:
            text = file.read()
            if text!=text_btn:
               self.ids.but_save.opacity = 1
            else:
                self.ids.but_save.opacity = 0.5

            file.close()

    def saving_text(self):

        with open(self.title_note, "r") as file:
            text = file.read()

            if text != self.text_note:

                with open(self.title_note, "w") as file:
                    file.write(self.text_note)
                    file.close()

                    self.ids.but_save.opacity = 0.5

            else:
                print('write something!!!! :| ' )

    #----------------------------title dialog-----------------------#

    #change title and close popup
    def title_change(self, btn):

        old_name = self.title_note
        self.title_note = f"{title_note_v[0]}.txt"
        os.rename(old_name, self.title_note)

        self.ids.note_title.text = self.title_note
        self.dialog_title.dismiss()

    # close title popup
    def close_title(self, btn):
        self.dialog_title.dismiss()

    #title change
    def popup_title(self):

        if not self.dialog_title:
            self.dialog_title = MDDialog(
                title = "Change Title",
                type = 'custom',
                content_cls = Title_Con(),
                size_hint=(0.4, 0.5),
                buttons = [
                    MDFlatButton(
                        text =  "cancel",
                        on_release = self.close_title
                    ),
                    MDFlatButton(
                        text = "save",
                        on_release = self.title_change
                    )
                ]

            )

        self.dialog_title.open()

    #-------------------------File option------------------------#

    #file management option
    def file_menu(self, btn):

        menu_items = [
            {
                'text':'[b]new file[/b]',
                'viewclass':'OneLineListItem',
                'height':45,
                'font_size':15,
                'on_release':lambda x='file':self.new_file()
            },
            {
                'text':'exit',
                'viewclass':'OneLineListItem',
                'height':45,
                'font_size':15,
                'on_release':lambda x='exit':self.exit_note()
            }
        ]

        self.menu_file = MDDropdownMenu(
            caller = btn,
            items = menu_items,
            width_mult = 2,
            radius = [8,24,24,24],
            max_height = 250
        )

        self.menu_file.open()

    #save file and create new file

    def new_file_save_save(self, btn):

        self.title_note = title_note_v[0]+".txt"

        create_file = open(self.title_note, "x")
        create_file.close()

        self.ids.note_input.text = ''

        self.dialog_new_file_save.dismiss()

    def new_file_save_cancel(self, btn):

        self.dialog_new_file_save.dismiss()

    def new_file_save(self, btn):

        self.dialog_new_file.dismiss()

        # save file
        with open(self.title_note, "w") as file:
            file.write(self.text_note)
            file.close()

        #create new file
        if not self.dialog_new_file_save:
            self.dialog_new_file_save = MDDialog(
                title  = "New file",
                type = 'custom',
                content_cls = Title_Con(),
                size_hint=(0.4, 0.5),
                buttons=[
                    MDFlatButton(
                        text = "save",
                        on_release = self.new_file_save_save
                    ),
                    MDFlatButton(
                    text = 'cancel',
                    on_release = self.new_file_save_cancel
                    )
                ]
            )

        self.dialog_new_file_save.open()

    #don't save file and create new file

    def new_file_dont_save_save(self, btn):

        self.title_note = title_note_v[0]+".txt"

        create_file = open(self.title_note, "x")
        create_file.close()

        self.ids.note_input.text = ''

        self.dialog_new_file_dont_save.dismiss()

    def new_file_dont_save_cancel(self, btn):

        self.dialog_new_file_dont_save.dismiss()

    def new_file_dont_save(self, btn):

        self.dialog_new_file.dismiss()

        if not self.dialog_new_file_dont_save:
            self.dialog_new_file_dont_save = MDDialog(
                title  = "New file",
                type = 'custom',
                content_cls = Title_Con(),
                size_hint=(0.4, 0.5),
                buttons=[
                    MDFlatButton(
                        text = "save",
                        on_release = self.new_file_dont_save_save
                    ),
                    MDFlatButton(
                    text = 'cancel',
                    on_release = self.new_file_dont_save_cancel
                    )
                ]
            )

        self.dialog_new_file_dont_save.open()

    #cancel to create new file
    def new_file_cancel(self, btn):
        self.dialog_new_file.dismiss()

    def new_Cfile_save(self, btn):

        self.title_note = title_note_v[0]+".txt"

        create_file = open(self.title_note, "x")
        create_file.close()

        self.ids.note_input.text = ''

        self.dialog_save_file.dismiss()

    def new_Cfile_cancel(self, btn):
        self.dialog_save_file.dismiss()

    #to create new file
    def new_file(self):

        with open(self.title_note, "r") as file:
            text = file.read()

            if text != self.text_note:

                if not self.dialog_new_file:

                    self.dialog_new_file = MDDialog(
                        title  = "New file",
                        text = "do you want to save this?",
                        type='custom',
                        size_hint=(0.5,0.5),
                        buttons=[
                            MDFlatButton(
                                text = "save",
                                on_release = self.new_file_save
                            ),
                            MDFlatButton(
                                text = 'don\'t save',
                                on_release = self.new_file_dont_save
                            ),
                            MDFlatButton(
                                text = 'cancel',
                                on_release = self.new_file_cancel
                            )
                        ]

                    )

                #open dialog of new file
                self.dialog_new_file.open()

            else:

                if not self.dialog_save_file:
                    self.dialog_save_file = MDDialog(
                        title  = "New file",
                        type = 'custom',
                        content_cls = Title_Con(),
                        size_hint=(0.4, 0.5),
                        buttons=[
                            MDFlatButton(
                                text = "save",
                                on_release = self.new_Cfile_save
                            ),
                            MDFlatButton(
                                text = 'cancel',
                                on_release = self.new_Cfile_cancel
                            )
                        ]

                    )

                self.dialog_save_file.open()

            file.close()

    #---------------------------file >>  exit----------------------------------#

    #save and exit from app
    def exit_save(self, btn):

        #save file
        with open(self.title_note, "w") as file:
            file.write(self.text_note)
            file.close()

        self.dialog_exit_note.dismiss()

        #exit the winodw
        MDApp.get_running_app().stop()
        Window.close()

    #don't save and exit from app
    def exit_dont_save(self, btn):

        self.dialog_exit_note.dismiss()

        MDApp.get_running_app().stop()
        Window.close()

    #cancel exit of note window
    def exit_cancel(self, btn):

        self.dialog_exit_note.dismiss()

    #exit a note
    def exit_note(self):

        with open(self.title_note, "r") as file:
            text = file.read()

            if text != self.text_note:

                if not self.dialog_exit_note:
                    self.dialog_exit_note = MDDialog(
                        title  = "New file",
                        text = "do you want to save this?",
                        type='custom',
                        size_hint=(0.5,0.5),
                        buttons=[
                            MDFlatButton(
                                text = "save",
                                on_release = self.exit_save
                            ),
                            MDFlatButton(
                                text = 'don\'t save',
                                on_release = self.exit_dont_save
                            ),
                            MDFlatButton(
                                text = 'cancel',
                                on_release = self.exit_cancel
                            )
                        ]

                    )

                #open dialog of new file
                self.dialog_exit_note.open()
            else:

                MDApp.get_running_app().stop()
                Window.close()

            file.close()

    #-------------------------Edit option------------------------#

    #edit to note option
    def edit_menu(self, btn):

        menu_items = [
            {
                'text':'[b]replace[/b]',
                'viewclass':'OneLineListItem',
                'height':45,
                'font_size':15,
                'on_release':lambda x='replace':self.replace_word()
            },
            {
                'text':'[b]emoji[/b]',
                'viewclass':'OneLineListItem',
                'height':45,
                'font_size':15,
                'on_release':lambda x='emoji':self.emoji()
            }
        ]

        self.menu_edit = MDDropdownMenu(
            caller = btn,
            items = menu_items,
            width_mult = 2.3,
            radius = [8,24,24,24],
            max_height = 250
        )

        self.menu_edit.open()

    #-------------------------Edit >> replace------------------------#

    def replace_save(self, btn):

        find = find_text_note[0]
        repl = replace_text_note[0]

        new_text = self.text_note.replace(find, repl)

        self.text_note = new_text
        self.ids.note_input.text = self.text_note

        self.dialog_replace_word.dismiss()

    def replace_cancel(self, btn):
        self.dialog_replace_word.dismiss()

    #replace word in passage
    def replace_word(self):

        if not self.dialog_replace_word:
            self.dialog_replace_word = MDDialog(
                title  = "Replace Word",
                type='custom',
                content_cls = Replace_Con(),
                size_hint = (0.5,0.5),
                buttons=[
                    MDFlatButton(
                        text = 'save',
                        on_release = self.replace_save
                    ),
                    MDFlatButton(
                        text = 'cancel',
                        on_release = self.replace_cancel
                    )
                ]

            )

        #open dialog of new file
        self.dialog_replace_word.open()

    #-------------------------Edit >> emoji------------------------#

    #exit the emoji
    def exit_emoji(self, but, *args):

        anime = Animation(height = 1, duration=0.2)

        but.clear_widgets()

        anime.start(but)

        self.emoji_task = False

    #emoji add in writer board
    def emoji_text(self, emoji):

        emo = emoji.text
        self.board.text += emo

    def make_emoji_btn(self, emoji_name, emoji_box, size):

        emoji = Button(text = f"{emoji_name}", font_size = 25, size_hint_x =  None, width = size, pos_hint = {'center_y': 0.5}, font_name = "comic", background_color = (0,0,0,0))
        emoji.bind(on_release = lambda x:self.emoji_text(emoji))
        emoji_box.add_widget(emoji)

    #add the taskbar
    def emoji(self, *args):

        emo = self.ids.emoji_show

        anime = Animation(height = 50, duration=0.2)

        #scroller
        scroll = ScrollView(bar_color = (0,0,0,0),bar_inactive_color = (0,0,0,0) ,do_scroll_y = False,size_hint_y = None,height = 45)

        #box of emoji

        emoji_box = BoxLayout(orientation = 'horizontal', size_hint_x = None, width = 1800)
        emoji_box.spacing = 20

        emoji_text = [
            " :-) ", "^_^", ":-D","(-■_■)", ":-(", ":-P", ";-)" , "(•_•)", "ಠ_ಠ", "(T_T)",
            " ╰(*°▽°*)╯ ", "  o('▽')o ", " (o'◡`o) ", " \_('_')_/ ", " (⊙_⊙;) ", " (¬_¬ ) "
        ]
        #emoji in box
        for i in range(15):
            if i > 8:
                self.make_emoji_btn(emoji_text[i], emoji_box, 100)
            else:
                self.make_emoji_btn(emoji_text[i], emoji_box, 55)

        # cancel button
        cross_btn = MDIconButton(icon = "close-circle-outline", pos_hint = {'center_y': .5})
        cross_btn.bind(on_release = lambda x: self.exit_emoji(emo))

        # emoji_box.add_widget(emoji)
        scroll.add_widget(emoji_box)

        emo.add_widget(scroll)
        emo.add_widget(cross_btn)

        if self.emoji_task == False:
            anime.start(emo)
            self.emoji_task=True

        elif self.emoji_task!= False:
            self.exit_emoji(emo)

    #-------------------------Help option------------------------#
    def help_menu(self, btn):

        menu_items =  [
            {
                'text':'[b]short cut[/b]',
                'viewclass':'OneLineListItem',
                'height':45,
                'font_size':15,
                'on_release':lambda x='short_cut':self.short_cut()
            },
            {
                'text':'[b]about[/b]',
                'viewclass':'OneLineListItem',
                'height':45,
                'font_size':15,
                'on_release':lambda x='about':self.about_note()
            },
        ]

        self.menu_help = MDDropdownMenu(
            caller = btn,
            items = menu_items,
            width_mult = 2.3,
            radius = [8,24,24,24],
            max_height = 150
        )

        self.menu_help.open()

    #-------------------------Help >> short cut------------------------#

    # close short cut dialog
    def close_short_cut(self, btn):
        self.dialog_short_cut.dismiss()

    #show a all short cut in note
    def short_cut(self):

        if not self.dialog_short_cut:
            self.dialog_short_cut = MDDialog(
                title="All Short Cut",
                type="custom",
                size_hint = (0.5, 0.5),
                content_cls=Short_Cut_Con(),
                buttons=[
                    MDFillRoundFlatButton(
                        text="ok",
                        on_release=self.close_short_cut
                    )
                ]

            )

        self.dialog_short_cut.open()

    #-------------------------Help >> about------------------------#

    # close about note dialog
    def close_about_note(self, btn):
        self.dialog_about_note.dismiss()

    #show about note
    def about_note(self):

        if not self.dialog_about_note:
            self.dialog_about_note = MDDialog(
                title='About Note',
                type='custom',
                size_hint = (0.6, 0.4),
                content_cls=About_Note_Con(),
                buttons = [
                    MDFillRoundFlatButton(
                        text="ok",
                        on_release=self.close_about_note
                    )
                ]
            )

        self.dialog_about_note.open()

    #------------------------Setting----------------------------#

    #drawer box for setting

    #open drawer box for setting
    def open_drawer(self,*args):

        anime = Animation(pos = (Window.size[0]-250,0), duration=0.2)

        set_draw = self.ids.setting_drawn

        anime.start(set_draw)

   #close drawer box for settig
    def colse_drawer(self,*args):

        anime = Animation(pos = (Window.size[0],0), duration=0.2)

        set_draw = self.ids.setting_drawn

        anime.start(set_draw)

    #color change in writer borad
    def red_color_text(self):
        self.ids.text_color.color = (1,0,0,1)
        self.board_text_color = (1,0,0,1)

    def yel_color_text(self):
        self.ids.text_color.color = (255/255, 215/255, 0/255,1)
        self.board_text_color = (255/255, 215/255, 0/255,1)

    def gre_color_text(self):
        self.ids.text_color.color = (0/255, 128/255, 0/255,1)
        self.board_text_color = (0/255, 128/255, 0/255,1)

    def pur_color_text(self):
        self.ids.text_color.color = (102/255, 51/255, 153/255, 1)
        self.board_text_color = (102/255, 51/255, 153/255, 1)

    def org_color_text(self):
        self.ids.text_color.color = (255/255, 140/255, 0/255, 1)
        self.board_text_color = (255/255, 140/255, 0/255, 1)

    #font change in write borad
    def font_Arial(self):
        self.board_text_name = "Arial"
        self.ids.text_name.font_name = "Arial"

    def font_Comic(self):
        self.board_text_name = "Comic"
        self.ids.text_name.font_name = "Comic"

    def font_Chiller(self):
        self.board_text_name = "Chiller"
        self.ids.text_name.font_name = "Chiller"

    def font_Forte(self):
        self.board_text_name = "Forte"
        self.ids.text_name.font_name = "Forte"

    def font_Gabriola(self):
        self.board_text_name = "Gabriola"
        self.ids.text_name.font_name = "Gabriola"

   #zoom

    def zoom_max(self):
        num = int(self.ids.zoom_num.text )

        num+=5

        self.board_zoom = num
        self.ids.zoom_num.text = str(num)

    def zoom_min(self):
        num = int(self.ids.zoom_num.text)

        num-=5

        if num<5:
            self.board_zoom = num
            self.ids.zoom_num.text = "10"

        else:
            self.board_zoom = num
            self.ids.zoom_num.text = str(num)

    #all set in setting
    def save_set(self):

        #text color
        self.board.color = self.board_text_color

        #text name
        self.board.font_name = self.board_text_name

        #zoom
        self.board.font_size = self.board_zoom

        #close to setting dialog
        set_drawn = self.ids.setting_drawn
        set_drawn.pos = (Window.size[0],0)

    #------------------------------Back-Arrow--------------------#

    def back_file(self):
        file_m = sm.get_screen("file")

        #clear file manager
        m = file_m.ids.note_manager
        m.clear_widgets()

        #refresh
        file_m.set_note()

        # change screen
        sm.current = "file"

#variable
#note name
note_name_v = [0]

#dialog of file create
class Create_file_Con(BoxLayout):

    def note_name(self, text):
        note_name_v[0] = text

#file manager
class File_Manager(Screen):

    dialog_file_create = None
    dialog_delete_file = None

    def __init__(self, **kw):
        super().__init__(**kw)

        self.file_note = ''
        self.file_list = {}

        self.set_note()

    #set note

    def set_note_save(self, filename):
        # main box
        file_manager = self.ids.note_manager

        file_note = filename

        #file
        File_card = MDCard(orientation = 'horizontal', size_hint_y = None, height = 45, padding = [10,0], radius = [20])
        self.ids[f"{file_note}"] = File_card

        #file open
        file_open_card = MDCard(orientation = 'horizontal', size_hint_y = None, height = 45, radius = [20])
        file_open_card.bind(on_release = lambda x: self.file_open(File_card))

        # file_open_card contents
        # button
        file_open_icon = MDIconButton(icon = "file-document-outline", pos_hint = {'center_y': 0.5}, size_hint_x = None)

        # note name
        file_open_name = MDLabel(text = f"[b]{file_note}[/b]",markup = True , font_size = 20)

        #file delete button
        file_delete_btn = MDIconButton(icon = "delete-outline")
        file_delete_btn.bind(on_release = lambda x: self.delete_file(File_card))

        # file_open_card contents are adding
        file_open_card.add_widget(file_open_icon)
        file_open_card.add_widget(file_open_name)

        #file_card contents are adding
        File_card.add_widget(file_open_card)
        File_card.add_widget(file_delete_btn)

        #file are adding in file_manager
        file_manager.add_widget(File_card)

        #adding file in file_list
        self.file_list.update({f"{File_card}":f"{file_note}"})

    def set_note(self):

        os.chdir("D:\\sweety\\Git_learn\\project\\gui_project\\file_manager")
        file_list_folder = os.listdir()
        num_file = len(file_list_folder)

        # main box
        file_manager = self.ids.note_manager

        #deleted extra space
        extra_spce = self.ids.extra_space
        file_manager.remove_widget(extra_spce)

        for i in range(num_file):
            self.set_note_save(file_list_folder[i])

        #extra space are adding bottom
        extra_label = Label()
        self.ids["extra_space"] = extra_label
        file_manager.add_widget(extra_label)

    #create file
    def create_file_save(self, btn):

        self.file_note = note_name_v[0] + ".txt"

        # create a file
        f = open(self.file_note, "x")
        f.close()

        # main box
        file_manager = self.ids.note_manager
        # delete the extra_space label
        extra_spce = self.ids.extra_space
        file_manager.remove_widget(extra_spce)

        File_card = MDCard(orientation = 'horizontal', size_hint_y = None, height = 45, padding = [10,0], radius = [20])
        self.ids[f"{self.file_note}"] = File_card

        file_open_card = MDCard(orientation = 'horizontal', size_hint_y = None, height = 45, radius = [20])
        file_open_card.bind(on_release = lambda x: self.file_open(File_card))

        # file_open_card contents

        # button
        file_open_icon = MDIconButton(icon = "file-document-outline", pos_hint = {'center_y': 0.5}, size_hint_x = None)

        # note name
        file_open_name = MDLabel(text = f"[b]{self.file_note}[/b]" ,markup = True , font_size = 20)

        #file delete button
        file_delete_btn = MDIconButton(icon = "delete-outline")
        file_delete_btn.bind(on_release = lambda x: self.delete_file(File_card))

        #extra space
        extra_label = Label()
        self.ids["extra_space"] = extra_label

        # file_open_card contents are adding
        file_open_card.add_widget(file_open_icon)
        file_open_card.add_widget(file_open_name)

        #file_card contents are adding
        File_card.add_widget(file_open_card)
        File_card.add_widget(file_delete_btn)

        #file are adding in file_manager
        file_manager.add_widget(File_card)
        file_manager.add_widget(extra_label)

        #adding file in file_list
        self.file_list.update({f"{File_card}":f"{self.file_note}"})

        self.dialog_file_create.dismiss()

    def create_file_cancel(self, btn):
        self.dialog_file_create.dismiss()

    def create_file(self):

        if not self.dialog_file_create:
            self.dialog_file_create = MDDialog(
                title='Create Note',
                type='custom',
                size_hint = (0.5, 0.4),
                content_cls=Create_file_Con(),
                buttons = [
                    MDFillRoundFlatButton(
                        text="save",
                        on_release=self.create_file_save
                    ),
                    MDFillRoundFlatButton(
                        text="cancel",
                        on_release=self.create_file_cancel
                    )
                ]
            )

        self.dialog_file_create.open()

    #open file
    def file_open(self, obj):
        note_file = self.file_list[str(obj)]

        #main
        main = sm.get_screen("main")

        #title name change
        main.ids.note_title.text = note_file
        main.title_note = note_file

        #give text to note
        with open(note_file, "r") as file:
            text = file.read()

            main.ids.note_input.text = text

            file.close()

        sm.current =  "main"

    #delete file
    def delete_file(self, obj):

        #del file in file_manage folder
        f = self.file_list[str(obj)]
        os.remove(f)

        #del file in note file_manager
        file_manage = self.ids.note_manager
        file_manage.remove_widget(obj)

        #del file in self.file_list
        self.file_list.pop(str(obj))

#main app
class Note(MDApp):
    icon = "note_icon.png"

    def build(self):
        # icon = "other/logo.png"

        # color theme of app
        self.theme_cls.theme_style = "Dark"
        self.theme_cls.primary_palette = "Gray"

        sm.add_widget(File_Manager(name='file'))
        sm.add_widget(Main(name="main"))

        return sm

#run app
App = Note()
App.run()


from django import forms
from django.forms import ModelForm
from core.forms.base import FormulaireBase
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Hidden, Submit, HTML, Fieldset, ButtonHolder, Div
from crispy_forms.bootstrap import Field, StrictButton, PrependedText, InlineField
from core.utils.utils_commandes import Commandes
from core.models import Facture, LotFactures
from core.widgets import DatePickerWidget, Select_avec_commandes

class Formulaire(FormulaireBase, ModelForm):
    date_edition = forms.DateField(label="Date d'émission", required=True, widget=DatePickerWidget())
    date_echeance = forms.DateField(label="Date d'échéance", required=False, widget=DatePickerWidget())
    lot = forms.ModelChoiceField(label="Lot de factures", queryset=LotFactures.objects.all(), required=False, widget=Select_avec_commandes(
                      {"donnees_extra": {}, "url_ajax": "ajax_modifier_lot_factures",
                       "textes": {"champ": "Nom du lot", "ajouter": "Saisir un lot de factures", "modifier": "Modifier un lot de factures"}}))

    class Meta:
        model = Facture
        fields = ["date_edition", "date_echeance", "lot"]

    def __init__(self, *args, **kwargs):
        idfamille = kwargs.pop("idfamille")
        super(Formulaire, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_id = 'famille_factures_form'
        self.helper.form_method = 'post'

        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-md-2'
        self.helper.field_class = 'col-md-10'

        # Affichage
        self.helper.layout = Layout(
            Commandes(annuler_url="{{ view.get_success_url }}", ajouter=False),
            Hidden('famille', value=idfamille),
            Field('date_edition'),
            Field('date_echeance'),
            Field('lot'),
        )


import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

dataset = pd.read_csv('Churn_Modelling.csv')
X = dataset.iloc[:, 3:-1].values
y = dataset.iloc[:, -1].values

# Preprocessing data
le = LabelEncoder()
X[:, 2] = le.fit_transform(X[:, 2])
print(X)

ct = ColumnTransformer(transformers=[('encoder', OneHotEncoder(), [1])], remainder='passthrough')  # we are transforming
X = np.array(ct.fit_transform(X))  # we are connecting and transforming our np.array
print(X)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

sc = StandardScaler()  # creating object of standard scaler
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
print(X_train)
print(X_test)

# Building the ANN
# Initialize the ANN as sequence of layers
ann = tf.keras.models.Sequential()  # creating ANN as a sequence of layers

# adding the input layer and the first hidden layer
ann.add(tf.keras.layers.Dense(units=6, activation='relu'))  # parameter units tell us how many neurons will be in a layer, the first hidden layer

# adding the second hidden layer
ann.add(tf.keras.layers.Dense(units=6, activation='relu'))

# Adding the output layer
ann.add(tf.keras.layers.Dense(units=1, activation='sigmoid'))  # the output should be binary so units are equal to 1

# Training the ANN
# compiling the ANN
ann.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])  # very important parameters

# training the ANN on the Training set
ann.fit(X_train, y_train, batch_size=32, epochs=100)

# Making the predictions and evaluating the model
# Predict the result of a single observations
print(ann.predict(sc.fit_transform([[1, 0, 0, 600, 1, 40, 3, 60000, 2, 1, 1, 50000]])) > 0.5)

# Predict the Test set reslut
y_pred = ann.predict(X_test)
y_pred = (y_pred > 0.5)  # making the binary outcome
print(np.concatenate((y_pred.reshape(len(y_pred), 1), y_test.reshape(len(y_test), 1)), 1))

# making the confusion Matrix
from sklearn.metrics import confusion_matrix, accuracy_score
cm = confusion_matrix(y_test, y_pred)
print(cm)
a_s = accuracy_score(y_test, y_pred)  # return a value of accuracy (1 is the highest value)
print(a_s)  # it returns how many corrected predictions we have in percentage


import json
import boto3
import re

def lambda_handler(event, context):
    data = event['detail']['requestParameters']
    if (data == None):
        print('User did not manage to create role')
    else:
        role_name = event['detail']['requestParameters']['roleName']
        iam_client = boto3.client('iam')
        iam_role = iam_client.get_role(RoleName=role_name)['Role']

        # Retrieve ID of the account in which the function is running
        this_account_id = context.invoked_function_arn.split(':')[4]

        # Expected AWS and Service Principals i.e., whitelisting
        expected_awsPrincipals = [this_account_id]
        expected_servicePrincipals = ['lambda']

        # Permission boundary (Pb) policy to be attached to the non-compliant role
        # Make sure the policy exists in the account where the Lambda function is running
        Pb_policy = 'arn:aws:iam::aws:policy/job-function/ViewOnlyAccess'

        # Check the principal in the role's trust policy
        assume_role_policy = iam_role['AssumeRolePolicyDocument']
        assume_role_principal = assume_role_policy['Statement'][0]['Principal']
        if ('AWS' in assume_role_principal):
            if type(assume_role_principal['AWS']) is list:
                awsPrincipals = assume_role_principal['AWS']
            else:
                # If there is only one AWS principal in the role's trust policy,
                # AWS returns a string instead of a list. Hence, we need to cast
                # string to list.
                awsPrincipals = [assume_role_principal['AWS']]

            # Check that the account numbers are in the approved list
            # If the account numbers are not in the approved list, attach that Pb_policy
            for principal in awsPrincipals:
                # AWS principal is typically in the format of arn:aws:iam::${Account_Id}:user/*
                # so we will take the first occurrence of the account id in the AWS principal string
                account_id = re.search(r'[0-9]{12}', principal).group()
                if account_id not in expected_awsPrincipals:
                    iam_client.put_role_permissions_boundary(RoleName=role_name, PermissionsBoundary=Pb_policy)
        else:
            # Define the regex pattern to find. Service principals are usually in the format of
            # <service-name>.amazonaws.com. We don't want .amazonaws.com so we are looking for
            # everything before the first period.
            find = re.compile(r"^[^.]*")
            if type(assume_role_principal['Service']) is list:
                servicePrincipals = assume_role_principal['Service']
            else:
                servicePrincipals = [assume_role_principal['Service']]

            for principal in servicePrincipals:
                # group() returns the whole match pattern
                service = re.search(find, principal).group()
                if service not in expected_servicePrincipals:
                    iam_client.put_role_permissions_boundary(RoleName=role_name, PermissionsBoundary=Pb_policy)


# -*- coding: utf-8 -*-
import logging
import os.path
import re
import tornado.web

from time import mktime, time
from datetime import datetime, timedelta

import tenjin
from tenjin.helpers import *
from tenjin.html import nl2br

from setting import *

import pylibmc
mc = pylibmc.Client()

###
def cur_time():
    return int(time())

def encode_dict(my_dict):
    newdict = {}
    for k in my_dict:
        #newdict[str(k)] = str(my_dict[k]).encode('utf-8')
        newdict[str(k)] = my_dict[k].encode('utf-8') if isinstance(my_dict[k], unicode) else str(my_dict[k])
    return "\x1e".join("%s\x1f%s" % x for x in newdict.iteritems())

def decode_dict(my_string):
    return dict(x.split("\x1f") for x in my_string.split("\x1e"))

def dict2utf8(my_dict):
    newdict = {}
    for k in my_dict:
        newdict[str(k)] = str(my_dict[k]).encode('utf-8')
        #newdict[str(k)] = my_dict[k].encode('utf-8') if isinstance(my_dict[k], unicode) else str(my_dict[k])
    return newdict

_re_html=re.compile('<.*?>|\&.*?\;', re.UNICODE|re.I|re.M|re.S)
def textilize(s):
    return _re_html.sub("", s).strip()

#_re_call = re.compile(r'@([a-z0-9]+)', re.UNICODE|re.I|re.M|re.S)
#_re_call = re.compile(r'(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9]+)', re.UNICODE|re.I|re.M|re.S)
_re_call = re.compile(r'\B\@([a-z0-9]+)', re.UNICODE|re.I|re.M|re.S)#同上
def call_member(text):
    members = _re_call.findall(text)
    if len(members) > 0:
        #for member in members:
        #    logging.error(member)
        return set([member for member in members])
    else:
        return None

# autolink
import string
LEADING_PUNCTUATION  = ['(', '<', '<']
TRAILING_PUNCTUATION = ['.', ',', ')', '>', '\n', '>']
punctuation_re = re.compile('^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % \
    ('|'.join([re.escape(x) for x in LEADING_PUNCTUATION]),
    '|'.join([re.escape(x) for x in TRAILING_PUNCTUATION])))
word_split_re = re.compile(r'(\s+)')
simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
def autolink(text, trim_url_limit=None, nofollow=True):
    """
    Converts any URLs in text into clickable links. Works on http://, https:// and
    www. links. Links can have trailing punctuation (periods, commas, close-parens)
    and leading punctuation (opening parens) and it'll still do the right thing.

    If trim_url_limit is not None, the URLs in link text will be limited to
    trim_url_limit characters.

    If nofollow is True, the URLs in link text will get a rel="nofollow" attribute.
    """
    trim_url = lambda x, limit=trim_url_limit: limit is not None and (x[:limit] + (len(x) >=limit and '...' or ''))  or x
    words = word_split_re.split(text)
    nofollow_attr = nofollow and ' rel="nofollow"' or ''
    for i, word in enumerate(words):
        match = punctuation_re.match(word)
        if match:
            lead, middle, trail = match.groups()
            if middle.startswith('www.') or ('@' not in middle and not middle.startswith('http://') and not middle.startswith('https://') and \
                    len(middle) > 0 and middle[0] in string.letters + string.digits and \
                    (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))):
                middle = '%s' % (middle, nofollow_attr, trim_url(middle))
            if middle.startswith('http://') or middle.startswith('https://'):
                middle = '%s' % (middle, nofollow_attr, trim_url(middle))
            if '@' in middle and not middle.startswith('www.') and not ':' in middle \
                and simple_email_re.match(middle):
                middle = '%s' % (middle, middle)
            if lead + middle + trail != word:
                words[i] = lead + middle + trail
    return ''.join(words)

# autolink end

#_re_imgs = re.compile('(http[s]?://?\S*\w\.(jpg|jpe|jpeg|gif|png))\w*', re.UNICODE|re.I|re.M|re.S)
_re_imgs = re.compile('(http[s]?://?[^ \f\n\r\t\v\?]*\w\.(jpg|jpe|jpeg|gif|png))\w*', re.UNICODE|re.I|re.M|re.S)
_re_mentions = re.compile('\B\@([a-z0-9]+)', re.UNICODE|re.I|re.M|re.S)
#http://v.youku.com/v_show/id_XNDQ4NTk5OTQw(.htm|.html)?
_re_youku = re.compile('http://v.youku.com/v_show/id_([a-zA-Z0-9\=]+)(\/|.html?)?', re.UNICODE|re.I|re.M|re.S)
#http://www.tudou.com/listplay/7cb57rueaYI/Op-E8hQrdRw(.htm|.html)?
#http://www.tudou.com/listplay/7cb57rueaYI
#http://www.tudou.com/programs/view/ro1Yt1S75bA/
_re_tudou = re.compile('http://www.tudou.com/(programs/view|listplay)/([a-zA-Z0-9\=\_\-]+)(\/|.html?)?', re.UNICODE|re.I|re.M|re.S)
#qq http://v.qq.com/boke/page/h/1/n/h04021dkn1n.html
_re_qq = re.compile('http://v.qq.com/(.+)/([a-zA-Z0-9]{8,}).(html?)', re.UNICODE|re.I|re.M|re.S)
#_re_urls = re.compile('(\w+:\/\/[^\s]+)', re.UNICODE|re.I|re.M|re.S)
_re_urls = re.compile('(\w+:\/\/[^\s]+)', re.UNICODE|re.I|re.M|re.S)
_re_gist = re.compile('(https?://gist.github.com/[\d]+)', re.UNICODE|re.I|re.M|re.S)
def content_formate(text, is_spider=False):
    #auto img
    if _re_imgs.search(text):
        if not is_spider:
            text = _re_imgs.sub(r'', text)
        else:
            text = _re_imgs.sub(r'', text)
    #mentions
    if '@' in text:
        #logging.error([yk for yk in _re_mentions.findall(text)])
        #for yk in _re_mentions.findall(text):
        #    logging.error(yk)
        text = _re_mentions.sub(r'@\1', text)
    #youku
    if 'v.youku.com' in text:
        text = _re_youku.sub(r'<embed src="http://player.youku.com/player.php/sid/\1/v.swf" quality="high" width="590" height="492" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"></embed>', text)
    #tudou
    if 'www.tudou.com' in text:
        text = _re_tudou.sub(r'<embed src="http://www.tudou.com/v/\2/&resourceId=0_05_05_99&iid=152278332&bid=05/v.swf" quality="high" width="590" height="492" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"></embed>', text)
    #qq
    if 'v.qq.com' in text:
        text = _re_qq.sub(r'<embed src="http://static.video.qq.com/TPout.swf?vid=\2&auto=0" allowFullScreen="true" quality="high" width="590" height="492" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash"></embed>', text)
    #gist
    if '://gist' in text:
        text = _re_gist.sub(r'',text)
    #url
    if 'http' in text:
        return autolink(text)
        #text = _re_urls.sub(r'\1', text)
    return text

def findall_mentions(text, filter_name=None):
    if '@' in text:
        ns = set([yk for yk in _re_mentions.findall(text.lower())])
        if filter_name:
            ns.discard(filter_name)
        if len(ns)<=NOTIFY_MEMBER_NUM:
            return ns
        else:
            return None
    else:
        return None

def safe_encode(con):
    return con.replace("<","<").replace(">",">")

def safe_decode(con):
    return con.replace("<","<").replace(">",">")

def clear_cache_multi(pathlist = None):
    if pathlist:
        mc.delete_multi([str(p) for p in pathlist])

def clear_all_cache():
    mc.flush_all()

def timestamp_to_datetime(timestamp):
    return datetime.fromtimestamp(int(timestamp))

def date_web(timestamp):
    it = int(timestamp)
    if (int(time())-it)<31536000:#365day
        time1 = datetime.fromtimestamp(it)
        time_diff = (datetime.utcnow() + timedelta(hours =+ 8)) - time1
        days = time_diff.days
        if days:
            if days > 60:
                return '%s 月前' % (days / 30)
            if days > 30:
                return '1 月前'
            if days > 14:
                return '%s 周前' % (days / 7)
            if days > 7:
                return '1 周前'
            if days > 1:
                return '%s 天前' % days
            return '1 天前'

        seconds = time_diff.seconds
        if seconds > 7200:
            return '%s 小时前' % (seconds / 3600)
        if seconds > 3600:
            return '1 小时前'
        if seconds > 120:
            return '%s 分钟前' % (seconds / 60)
        if seconds > 60:
            return '1 分钟前'
        if seconds > 1:
            return '%s 秒钟前' %seconds
        return '%s 秒钟前' % seconds

    else:
        return datetime.fromtimestamp(it).strftime('%Y-%m-%d %H:%M:%S')

def date_web2(timestamp):
    #2011-12-12 23:26:41
    return datetime.fromtimestamp(int(timestamp)).strftime('%Y-%m-%d %H:%M:%S')

def date_item(timestamp):
    #2011-12-12
    return datetime.fromtimestamp(int(timestamp)).strftime('%Y-%m-%d')

#
def memcached(key, cache_time=DEFAULT_CACHE_TIME, key_suffix_calc_func=None):
    def wrap(func):
        def cached_func(*args, **kw):

            key_with_suffix = key
            if key_suffix_calc_func:
                key_suffix = key_suffix_calc_func(*args, **kw)
                if key_suffix is not None:
                    key_with_suffix = '%s:%s' % (key, key_suffix)

            key_with_suffix = str(key_with_suffix)

            mc = pylibmc.Client()
            value = mc.get(key_with_suffix)
            if value is None:
                value = func(*args, **kw)
                mc.set(key_with_suffix, value, cache_time)
            return value
        return cached_func
    return wrap

###
engine = tenjin.Engine(path=[os.path.join('templates', THEME), 'templates'], cache=tenjin.MemoryCacheStorage(), preprocess=True)
class BaseHandler(tornado.web.RequestHandler):

    __SPIDER_PATTERN = re.compile('(bot|crawl|spider|slurp|sohu-search|lycos|robozilla|google)', re.I)

    def render(self, template, context=None, globals=None, layout=False):
        if context is None:
            context = {}
        context.update({
            'cur_user':self.cur_user(),
            'is_spider': self.is_spider(),
            'request': self.request,
        })

        context['qq_login_url'] = ''
        if USER_MODEL in [1,3]:
            if not context['cur_user']:
                from qqweibo import APIClient as qqAPIClient
                qqclient = qqAPIClient(app_key=QQ_APP_ID, app_secret=QQ_APP_KEY)
                context['qq_login_url'] = qqclient.get_authorize_url()
                #建议把qq_login_url 值设为静态（如下示例），并把上面三行屏蔽掉
                #context['qq_login_url'] = 'https://graph.qq.com/oauth2.0/authorize?scope=get_user_info&redirect_uri=http%3A//myskoda.sinaapp.com/qqcallback&response_type=code&client_id=100305902'

        return engine.render(template, context, globals, layout)

    def echo(self, template, context=None, globals=None, layout=False):
        self.write(self.render(template, context, globals, layout))

    @memcached('cur_user', 600, lambda self: self.get_cookie('username', ''))
    def cur_user(self):
        user_name_cookie = self.get_cookie('username','')
        user_code_cookie = self.get_cookie('usercode','')
        if user_name_cookie and user_code_cookie:
            from model import Member
            return Member.check_loged_user(user_name_cookie, user_code_cookie)
        else:
            return None

    def is_spider(self):
        user_agent = self.request.headers.get('user-agent','')
        return self.__SPIDER_PATTERN.search(user_agent) is not None

def authorized(url='/login', flag = 2):
    def wrap(handler):
        def authorized_handler(self, *args, **kw):
            request = self.request
            user_name_cookie = self.get_cookie('username','')
            user_code_cookie = self.get_cookie('usercode','')
            if user_name_cookie and user_code_cookie:
                from model import Member
                user = Member.check_loged_user(user_name_cookie, user_code_cookie, flag)
            else:
                user = False
            if request.method == 'GET':
                if not user:
                    self.redirect(url)
                    return False
                else:
                    handler(self, *args, **kw)
            else:
                if not user:
                    self.set_status(403)
                    #self.error(403)
                else:
                    handler(self, *args, **kw)
        return authorized_handler
    return wrap


# -*- coding: utf-8 -*-
# © 2014-2016 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging
from datetime import datetime
from odoo import models, fields, api, _
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)

class AccountBankStatementImport(models.TransientModel):
    _inherit = 'account.bank.statement.import'

    _excluded_accounts = []

    def _parse_cfonb_amount(self, amount_str, nb_of_dec):
        """Taken from the cfonb lib"""
        amount_str = amount_str[:-nb_of_dec] + '.' + amount_str[-nb_of_dec:]
        # translate the last char and set the sign
        credit_trans = {
            'A': '1', 'B': '2', 'C': '3', 'D': '4', 'E': '5',
            'F': '6', 'G': '7', 'H': '8', 'I': '9', '{': '0'}
        debit_trans = {
            'J': '1', 'K': '2', 'L': '3', 'M': '4', 'N': '5',
            'O': '6', 'P': '7', 'Q': '8', 'R': '9', '}': '0'}
        assert (
            amount_str[-1] in debit_trans or amount_str[-1] in credit_trans),\
            'Invalid amount in CFONB file'
        if amount_str[-1] in debit_trans:
            amount_num = float(
                '-' + amount_str[:-1] + debit_trans[amount_str[-1]])
        elif amount_str[-1] in credit_trans:
            amount_num = float(amount_str[:-1] + credit_trans[amount_str[-1]])
        return amount_num

    def _get_cfonb_st_name(self, account_number, start_date_str, end_date_str):
        name = _('Account %s  %s > %s'
                 ) % (account_number, start_date_str, end_date_str)
        return name

    @api.model
    def _check_cfonb(self, data_file):
        return data_file.strip().startswith('01')

    @api.model
    def _parse_file(self, data_file):
        """ Import a file in French CFONB format"""
        cfonb = self._check_cfonb(data_file)
        if not cfonb:
            return super(AccountBankStatementImport, self)._parse_file(
                data_file)
        transactions = []
        if not data_file.splitlines():
            raise UserError(_('The file is empty.'))
        i = 0
        seq = 1
        bank_code = guichet_code = account_number = currency_code = False
        decimals = start_balance = False
        start_balance = end_balance = False
        vals_line = False
        # The CFONB spec says you should only have digits, capital letters
        # and * - . /
        # But many banks don't respect that and use regular letters for exemple
        # And I found one (LCL) that even uses caracters with accents
        # So the best method is probably to decode with latin1
        data_file_decoded = data_file.decode('latin1')
        for line in data_file_decoded.splitlines():
            i += 1
            _logger.debug("Line %d: %s" % (i, line))
            if not line:
                continue
            if len(line) != 120:
                raise UserError(_(
                    'Line %d is %d caracters long. All lines of a '
                    'CFONB bank statement file must be 120 caracters long.')
                    % (i, len(line)))
            rec_type = line[0:2]
            line_bank_code = line[2:7]
            line_guichet_code = line[11:16]
            line_account_number = line[21:32]
            # Some LCL files are invalid: they leave decimals and
            # currency fields empty on lines that start with '01' and '07',
            # so I give default values in the code for those fields
            line_currency_code = line[16:19] != '   ' and line[16:19] or 'EUR'
            decimals = line[19:20] != ' ' and int(line[19:20]) or 2
            date_cfonb_str = line[34:40]
            date_dt = False
            date_str = False
            if line_account_number in self._excluded_accounts:
                continue
            if date_cfonb_str != '      ':
                date_dt = datetime.strptime(date_cfonb_str, '%d%m%y')
                date_str = fields.Date.to_string(date_dt)
            assert decimals == 2, 'We use 2 decimals in France!'

            if i == 1:
                bank_code = line_bank_code
                guichet_code = line_guichet_code
                currency_code = line_currency_code
                account_number = line_account_number
                if rec_type != '01':
                    raise UserError(_(
                        "The 2 first letters of the first line are '%s'. "
                        "A CFONB file should start with '01'") % rec_type)
                start_balance = self._parse_cfonb_amount(
                    line[90:104], decimals)
                start_date_str = date_str

            if (
                    bank_code != line_bank_code or
                    guichet_code != line_guichet_code or
                    currency_code != line_currency_code or
                    account_number != line_account_number):
                raise UserError(_(
                    'Only single-account files and single-currency '
                    'files are supported for the moment. It is not '
                    'the case starting from line %d.') % i)

            if rec_type in ('04', '01', '07') and vals_line:
                # I save the previous line
                # This trick is needed for the 05 lines
                transactions.append(vals_line)
                vals_line = False
            if rec_type == '07':
                end_balance = self._parse_cfonb_amount(line[90:104], decimals)
                end_date_str = date_str
            elif rec_type == '04':
                bank_account_id = partner_id = False
                amount = self._parse_cfonb_amount(line[90:104], decimals)
                ref = line[81:88].strip()  # This is not unique
                name = line[48:79].strip()
                vals_line = {
                    'sequence': seq,
                    'date': date_str,
                    'name': name,
                    'ref': ref,
                    'unique_import_id':
                    '%s-%s-%.2f-%s' % (date_str, ref, amount, name),
                    'amount': amount,
                    'partner_id': partner_id,
                    'bank_account_id': bank_account_id,
                }
                seq += 1
            elif rec_type == '05':
                assert vals_line, 'vals_line should have a value !'
                complementary_info_type = line[45:48]
                if complementary_info_type in ('   ', 'LIB'):
                    name_append = ' ' + line[48:118].strip()
                    vals_line['name'] += name_append
                    vals_line['unique_import_id'] += name_append

        st_name = self._get_cfonb_st_name(account_number,
                                          start_date_str, end_date_str)

        vals_bank_statement = {
            'name': st_name,
            'date': end_date_str,
            'balance_start': start_balance,
            'balance_end_real': end_balance,
            'transactions': transactions,
            }
        return currency_code, account_number, [vals_bank_statement]