
from kivy.properties import ObjectProperty, StringProperty, ListProperty
from datetime import datetime, timedelta
from kivy.core.text import LabelBase
from kivy.metrics import dp
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import Image
from kivymd.app import MDApp
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.datatables import MDDataTable
import random

import csv
from kivymd.uix.textfield import MDTextField
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivymd.uix.label import MDLabel
from kivy.uix.label import Label

from kivy.utils import platform
from kivy.clock import Clock
from kivy.uix.widget import Widget

from kivy.graphics import Color, Rectangle
from kivy_garden.graph import Graph, LinePlot

from modbus_tk.modbus_tcp import TcpMaster
import modbus_tk.defines as cst
import socket

from random import randint  
from kivymd.theming import ThemeManager

LabelBase.register(name="MPoppins", fn_regular="fonts/Chinese/msyh.ttf")
LabelBase.register(name="BPoppins", fn_regular="fonts/Chinese/msyh.ttf")
LabelBase.register(name="RRubik",   fn_regular="fonts/Chinese/msyh.ttf")
LabelBase.register(name="RCro",     fn_regular="fonts/Chinese/msyh.ttf")
LabelBase.register(name="RPac",     fn_regular="fonts/Chinese/msyh.ttf")



def get_books():
    pass

class MainScreen(Screen):
    pass
class HomeScreen(Screen):
    home = ObjectProperty(None)
class LoginScreen(Screen):
    login = ObjectProperty(None)
class ProfileScreen(Screen):
    profile = ObjectProperty(None)
class ProfileEditScreen(Screen):
    profile_edit = ObjectProperty(None)
class HistoryScreen(Screen):
    history = ObjectProperty(None)

class ModifyCurrentParamScreen(Screen):
    modify_current_param = ObjectProperty(None)
class ModifyVoltageParamScreen(Screen):
    modify_voltage_param = ObjectProperty(None)
class ModifyLeakageParamScreen(Screen):
    modify_leakage_param = ObjectProperty(None)
class ModifySystemParamScreen(Screen):
    modify_system_param = ObjectProperty(None)
class ModifyProtectionParamScreen(Screen):
    modify_protection_param = ObjectProperty(None)
class RealTimeCurveScreen(Screen):
    real_time_curve = ObjectProperty(None)
class ControlCommandScreen(Screen):
    control_command = ObjectProperty(None)
class AboutScreen(Screen):
    about = ObjectProperty(None)


class SignUpScreen(Screen):
    signup = ObjectProperty(None)
class ForgetPassScreen(Screen):
    forget_Password = ObjectProperty(None)
class OtpScreen(Screen):
    otp = ObjectProperty(None)
class ResetPassScreen(Screen):
    reset_pass = ObjectProperty(None)
class SearchBookScreen(Screen):
    search_book = ObjectProperty(None)
class NotificationScreen(Screen):
    notifications = ObjectProperty(None)
class RecommendScreen(Screen):
    recommendation = ObjectProperty(None)
class BorrowBookScreen(Screen):
    borrow_book = ObjectProperty(None)
class ReturnBookScreen(Screen):
    return_book = ObjectProperty(None)
class RenewBookScreen(Screen):
    renew_book = ObjectProperty(None)




# Window.size = (dp(360), dp(680))

class app(MDApp):
    wifi_status_text = StringProperty("")
    def __init__(self):
        super().__init__()
        self.signup_sem = None
        self.signup_branch = None
        self.user_name = None
        self.book_pos_name = None
        self.book_pos = None
        self.rec_label = None
        self.rec_grid = None
        self.recommend_screen = None
        self.book_input = None
        self.data_tables = None
        self.search_grid = None
        self.search_field = None
        self.renew_grid = None
        self.renewable_books = []
        self.renew = self.renewable_books
        self.history_grid = None
        self.books_history = []
        self.history = self.books_history
        self.image_label_grid = None
        self.books = []
        self.items = self.books
        self.book_name = None
        self.isbn = None
        self.a = None
        self.back_button = None
        self.user = None
        self.dialog = None
        self.dialog2 = None
        self.profile_edit_screen = None
        self.edit_email = None
        self.edit_prn = None
        self.edit_name = None
        self.edit_number = None
        self.edit_branch = None
        self.profile_semester = None
        self.profile_branch = None
        self.profile_number = None
        self.profile_prn = None
        self.profile_email = None
        self.profile_name = None
        self.user_no = None
        self.user_email = None
        self.user_prn = None
        self.d2 = None
        self.d3 = None
        self.d4 = None
        self.user_pass = None
        self.d1 = None
        self.edit_semester = None
        self.otp_button = None
        self.new_pass = None
        self.new_pass1 = None
        self.mobile_no = None
        self.password = None
        self.username = None

        self.modbus_master = None  # Modbus连接对象
        self.modbus_ip = None      # Modbus服务器IP
        self.modbus_port = None    # Modbus服务器端口


        self.theme_cls.font_styles["H1"]    =       ["BPoppins", 96, False, -1.5]
        self.theme_cls.font_styles["H2"]    =       ["BPoppins", 60, False, -0.5]
        self.theme_cls.font_styles["H3"]    =       ["BPoppins", 48, False, 0]
        self.theme_cls.font_styles["H4"]    =       ["BPoppins", 34, False, 0.25]
        self.theme_cls.font_styles["H5"]    =       ["BPoppins", 25, False, 0.15]
        self.theme_cls.font_styles["H6"]    =       ["BPoppins", 16, False, 0.15]
        self.theme_cls.font_styles["Subtitle1"] =   ["BPoppins", 16, False, 0.15]
        self.theme_cls.font_styles["Subtitle2"] =   ["BPoppins", 14, False, 0.1]
        self.theme_cls.font_styles["Body1"] =       ["BPoppins", 16, False, 0.5]
        self.theme_cls.font_styles["Body2"] =       ["BPoppins", 14, False, 0.25]
        self.theme_cls.font_styles["Button"] =      ["BPoppins", 14, True, 1.25]
        self.theme_cls.font_styles["Caption"] =     ["BPoppins", 13, False, 0.15]
        self.theme_cls.font_styles["Overline"] =    ["BPoppins", 10, True, 1.5]

    def build(self):
        Builder.load_file('kv/app.kv')
        screen_manager = ScreenManager()
        screen_manager.add_widget(MainScreen(name="main"))
        screen_manager.add_widget(HomeScreen(name="home"))
        screen_manager.add_widget(LoginScreen(name="login"))
        screen_manager.add_widget(HistoryScreen(name="history"))
        screen_manager.add_widget(ProfileScreen(name="profile"))
        screen_manager.add_widget(ProfileEditScreen(name="profile_edit"))
        
        screen_manager.add_widget(ModifyCurrentParamScreen(name="modify_current_param"))
        screen_manager.add_widget(ModifyVoltageParamScreen(name="modify_voltage_param"))
        screen_manager.add_widget(ModifyLeakageParamScreen(name="modify_leakage_param"))
        screen_manager.add_widget(ModifySystemParamScreen(name="modify_system_param"))
        screen_manager.add_widget(ModifyProtectionParamScreen(name="modify_protection_param"))
        screen_manager.add_widget(RealTimeCurveScreen(name="real_time_curve"))
        screen_manager.add_widget(ControlCommandScreen(name="control_command"))
        screen_manager.add_widget(AboutScreen(name="about"))

        screen_manager.add_widget(SignUpScreen(name="signup"))
        screen_manager.add_widget(ForgetPassScreen(name="forgot_pass"))
        screen_manager.add_widget(OtpScreen(name="otp"))
        screen_manager.add_widget(ResetPassScreen(name="reset_pass"))
        screen_manager.add_widget(NotificationScreen(name="notification"))
        screen_manager.add_widget(SearchBookScreen(name="searchBook"))
        screen_manager.add_widget(RecommendScreen(name="recommend"))
        screen_manager.add_widget(BorrowBookScreen(name="borrow_book"))
        screen_manager.add_widget(ReturnBookScreen(name="return_book"))
        screen_manager.add_widget(RenewBookScreen(name="renew_book"))


        Clock.schedule_once(self.update_wifi_status, 2)


        # Clock.schedule_interval(self.update_register_display, 1)

        return screen_manager

#############################################ALL INPUT TEXT############################################################
    def on_start(self):
        
        # 从根窗口中获取名为"login"的屏幕（登录界面）
        login_screen = self.root.get_screen("login")
        # 通过界面ID获取登录界面中的用户名输入框组件
        # self.username = login_screen.ids.username
        # 通过界面ID获取登录界面中的密码输入框组件
        # self.password = login_screen.ids.password

        # 从根窗口中获取名为"home"的屏幕（主界面）
        home_screen = self.root.get_screen("home")
        # 通过界面ID获取主界面中的用户信息组件
        self.user = home_screen.ids.user
        # 通过界面ID获取主界面中的书架位置名称组件
        self.book_pos_name = home_screen.ids.book_pos_name
        # 通过界面ID获取主界面中的书架位置组件
        self.book_pos = home_screen.ids.book_pos

        # 从根窗口中获取名为"forgot_pass"的屏幕（忘记密码界面）
        forgot_pass_screen = self.root.get_screen("forgot_pass")
        # 通过界面ID获取忘记密码界面中的手机号输入框组件
        self.mobile_no = forgot_pass_screen.ids.forgotPass_no

        # 从根窗口中获取名为"reset_pass"的屏幕（重置密码界面）
        reset_pass_screen = self.root.get_screen("reset_pass")
        # 通过界面ID获取重置密码界面中的新密码输入框组件
        self.new_pass = reset_pass_screen.ids.new_pass
        # 通过界面ID获取重置密码界面中的确认新密码输入框组件
        self.new_pass1 = reset_pass_screen.ids.new_pass1

        # 从根窗口中获取名为"otp"的屏幕（验证码界面）
        otp_screen = self.root.get_screen("otp")
        # 通过界面ID获取验证码界面中的"验证"按钮组件
        self.otp_button = otp_screen.ids.otp_button
        # 通过界面ID获取验证码界面中的"返回"按钮组件
        self.back_button = otp_screen.ids.back_button
        # 通过界面ID获取验证码界面中的第一个数字输入框组件
        self.d1 = otp_screen.ids.d1
        # 通过界面ID获取验证码界面中的第二个数字输入框组件
        self.d2 = otp_screen.ids.d2
        # 通过界面ID获取验证码界面中的第三个数字输入框组件
        self.d3 = otp_screen.ids.d3
        # 通过界面ID获取验证码界面中的第四个数字输入框组件
        self.d4 = otp_screen.ids.d4

        # 从根窗口中获取名为"signup"的屏幕（注册界面）
        # signup_screen = self.root.get_screen("signup")
        # 通过界面ID获取注册界面中的用户名输入框组件
        # self.user_name = signup_screen.ids.signup_name
        # 通过界面ID获取注册界面中的PRN（可能是学号/身份标识）输入框组件
        # self.user_prn = signup_screen.ids.signup_prn
        # 通过界面ID获取注册界面中的邮箱输入框组件
        # self.user_email = signup_screen.ids.signup_email
        # 通过界面ID获取注册界面中的手机号输入框组件
        # self.user_no = signup_screen.ids.signup_no
        # 通过界面ID获取注册界面中的密码输入框组件
        # self.user_pass = signup_screen.ids.signup_pass
        # 通过界面ID获取注册界面中的所属部门/专业选择组件
        # self.signup_branch = signup_screen.ids.signup_branch
        # 通过界面ID获取注册界面中的年级/学期选择组件
        # self.signup_sem = signup_screen.ids.signup_sem

        # 从根窗口中获取名为"profile"的屏幕（个人资料界面）
        profile_screen = self.root.get_screen("profile")
        # 通过界面ID获取个人资料界面中的姓名展示组件
        self.profile_name = profile_screen.ids.profile_name
        # 通过界面ID获取个人资料界面中的邮箱展示组件
        self.profile_email = profile_screen.ids.profile_email
        # 通过界面ID获取个人资料界面中的PRN（身份标识）展示组件
        self.profile_prn = profile_screen.ids.profile_prn
        # 通过界面ID获取个人资料界面中的手机号展示组件
        self.profile_number = profile_screen.ids.profile_number
        # 通过界面ID获取个人资料界面中的所属部门/专业展示组件
        self.profile_branch = profile_screen.ids.profile_branch
        # 通过界面ID获取个人资料界面中的年级/学期展示组件
        self.profile_semester = profile_screen.ids.profile_semester

        # 从根窗口中获取名为"profile_edit"的屏幕（个人资料编辑界面）
        self.profile_edit_screen = self.root.get_screen("profile_edit")
        # 通过界面ID获取资料编辑界面中的姓名编辑输入框组件
        self.edit_name = self.profile_edit_screen.ids.edit_name
        # 通过界面ID获取资料编辑界面中的邮箱编辑输入框组件
        self.edit_email = self.profile_edit_screen.ids.edit_email
        # 通过界面ID获取资料编辑界面中的PRN（身份标识）编辑输入框组件
        self.edit_prn = self.profile_edit_screen.ids.edit_prn
        # 通过界面ID获取资料编辑界面中的手机号编辑输入框组件
        self.edit_number = self.profile_edit_screen.ids.edit_no
        # 通过界面ID获取资料编辑界面中的所属部门/专业编辑选择组件
        self.edit_branch = self.profile_edit_screen.ids.edit_branch
        # 通过界面ID获取资料编辑界面中的年级/学期编辑选择组件
        self.edit_semester = self.profile_edit_screen.ids.edit_sem

        # 从根窗口中获取名为"borrow_book"的屏幕（借书界面）
        borrow_screen = self.root.get_screen("borrow_book")
        # 通过界面ID获取借书界面中的ISBN（图书编号）输入框组件
        self.isbn = borrow_screen.ids.isbn

        # 从根窗口中获取名为"return_book"的屏幕（还书界面）
        return_book_screen = self.root.get_screen("return_book")
        # 通过界面ID获取还书界面中的图片与标签网格布局组件
        self.image_label_grid = return_book_screen.ids.image_label_grid

        # 从根窗口中获取名为"renew_book"的屏幕（图书续借界面）
        renew_book_screen = self.root.get_screen("renew_book")
        # 通过界面ID获取续借界面中的网格布局组件
        self.renew_grid = renew_book_screen.ids.renew_grid

        # 从根窗口中获取名为"history"的屏幕（借阅历史界面）
        history_screen = self.root.get_screen("history")
        # 通过界面ID获取借阅历史界面中的网格布局组件
        self.history_grid = history_screen.ids.history_grid

        # 从根窗口中获取名为"searchBook"的屏幕（图书搜索界面）
        search_book_screen = self.root.get_screen("searchBook")
        # 通过界面ID获取图书搜索界面中的搜索输入框组件
        self.search_field = search_book_screen.ids.search_field
        # 通过界面ID获取图书搜索界面中的搜索结果网格布局组件
        self.search_grid = search_book_screen.ids.search_grid

        # 从根窗口中获取名为"recommend"的屏幕（图书推荐界面）
        self.recommend_screen = self.root.get_screen("recommend")
        # 通过界面ID获取推荐界面中的图书输入框组件
        self.book_input = self.recommend_screen.ids.book_input
        # 通过界面ID获取推荐界面中的推荐结果网格布局组件
        self.rec_grid = self.recommend_screen.ids.rec_grid
        # 通过界面ID获取推荐界面中的推荐信息标签组件
        self.rec_label = self.recommend_screen.ids.rec_label

        self.root.bind(current=self.on_screen_changed)
        self.register_update_event = None

    def on_screen_changed(self, instance, value):
        """屏幕切换时启动/停止刷新"""
        if value == "real_time_curve":
            # 进入目标屏幕时启动定时刷新
            if not self.register_update_event:
                self.register_update_event = Clock.schedule_interval(self.update_register_display, 1)
        else:
            # 离开时停止刷新
            if self.register_update_event:
                self.register_update_event.cancel()
                self.register_update_event = None

    # def update_register_display(self, dt):
    #     """更新原标签的显示内容"""
    #     # 仅在目标屏幕时更新
    #     if self.root.current != "real_time_curve":
    #         return
    #     # 读取值并更新到原标签
    #     value = self.read_modbus_register()
    #     real_time_screen = self.root.get_screen("real_time_curve")
    #     real_time_screen.ids.register_label.text = f"寄存器 0: {value}"  # 直接更新原标签

    def write_modbus_register(self, slave_id=1, address=0, value=None):
        """
        写入Modbus保持寄存器（单个寄存器）
        :param slave_id: 从机ID（默认1）
        :param address: 寄存器地址（默认0）
        :param value: 要写入的值（必须为整数，16位范围内：0-65535）
        :return: 操作结果字符串
        """
        # 检查Modbus连接是否初始化
        if not self.modbus_master:
            return "错误：Modbus未连接，请先初始化连接"
        
        # 检查写入值是否有效
        if value is None:
            return "错误：未指定要写入的值"
        try:
            # 转换为整数并检查范围（Modbus保持寄存器通常为16位无符号整数）
            write_value = int(value)
            if not (0 <= write_value <= 65535):
                return "错误:值必须在0-65535范围内(16位无符号整数)"
        except ValueError:
            return "错误：写入值必须为整数"
        
        try:
            # 使用正确的写入函数：WRITE_SINGLE_REGISTER（写入单个寄存器）
            self.modbus_master.execute(
                slave=slave_id,
                function_code=cst.WRITE_SINGLE_REGISTER,
                starting_address=address,
                output_value=write_value  # 注意参数名是output_value
            )
            return f"成功:从机ID={slave_id}，寄存器地址={address}，写入值={write_value}"
        except Exception as e:
            # 捕获异常并返回错误信息
            error_msg = f"失败:从机ID={slave_id}，寄存器地址={address}，错误信息：{str(e)}"
            print(error_msg)
            return error_msg

    def modify_register(self, input_text):
        """处理修改请求，修改后更新原标签"""
        if not input_text:
            self.show_dialog("错误", "请输入值")
            return
        
        try:
            value = int(input_text)
            # 这里假设写入 从机ID=1，地址=0 的寄存器
            # 若需要动态指定，可从界面控件中获取（例如：self.ids.slave_id.text）
            result = self.write_modbus_register(
                slave_id=1,
                address=0,
                value=value
            )
            self.show_dialog("操作结果", result)
            # 若成功，立即刷新显示
            if "成功" in result:
                self.update_register_display(0)  # 0是dt参数占位符
        except ValueError:
            self.show_dialog("错误", "请输入有效整数")

    def show_dialog(self, title, message):
        self.dialog1(message,title)
#############################################@Frequently used functions##################################################

    @staticmethod
    def change_cursor(is_enter):
        """改变鼠标指针样式"""
        # 如果is_enter为True（鼠标进入目标区域），将鼠标指针改为手型
        if is_enter:
            Window.set_system_cursor('hand')
        # 否则（鼠标离开目标区域），将鼠标指针改回默认箭头样式
        else:
            Window.set_system_cursor('arrow')

    @staticmethod
    def toggle_password_visibility(password_field, icon_button):
        """切换密码输入框的可见性状态"""
        # 检查密码输入框当前是否处于密码隐藏状态
        if password_field.password:
            # 如果是隐藏状态，切换为可见状态
            password_field.password = False
            # 更新图标为"eye"（眼睛图标，表示当前可见）
            icon_button.icon = "eye"
        else:
            # 如果是可见状态，切换为隐藏状态（显示为圆点/星号）
            password_field.password = True
            # 更新图标为"eye-off"（闭眼图标，表示当前隐藏）
            icon_button.icon = "eye-off"

    def clear_text(self):
        """清空界面中所有输入框和文本组件的内容"""
        # 清空图书搜索框内容
        self.search_field.text = ""
        # 清空图书推荐输入框内容
        self.book_input.text = ""
        # 清空登录界面的用户名输入框内容
        # self.username.text = ""
        # 清空登录界面的密码输入框内容
        # self.password.text = ""
        # 清空忘记密码界面的手机号输入框内容
        self.mobile_no.text = ""
        # 清空验证码界面的第一个输入框内容
        self.d1.text = ""
        # 清空验证码界面的第二个输入框内容
        self.d2.text = ""
        # 清空验证码界面的第三个输入框内容
        self.d3.text = ""
        # 清空验证码界面的第四个输入框内容
        self.d4.text = ""
        # 清空书架位置名称文本内容
        self.book_pos_name.text = ""
        # 重置书架位置说明文本为示例内容
        self.book_pos.text = "测试内容示例"
        # 再次清空手机号输入框（可能是为了确保完全清空）
        self.mobile_no.text = ""
        # 清空借书界面的ISBN输入框内容
        self.isbn.text = ''

    def on_press_back_arrow(self):
        # self.username.text = ""
        # self.password.text = ""
        self.mobile_no.text = ""
        self.d1.text = ""
        self.d2.text = ""
        self.d3.text = ""
        self.d4.text = ""

    def focus_text_field(self, icon_button, focus, page):
        if focus:
            icon_button.icon_color = self.theme_cls.primary_color
        elif page == "password":
            icon_button.icon_color = 162 / 255, 169 / 255, 188 / 255, 1
        elif page == "sign_pass":
            icon_button.icon_color = 217 / 255, 217 / 255, 217 / 255, 1
        else:
            pass

    def otp_button_fun(self, obj):
        if obj == "True":
            self.otp_button.text = "Reset Password"
        elif obj == "1":
            self.otp_button.text = "Edit Credentials"
        elif obj == "2":
            self.otp_button.text = "Verify OTP"
        else:
            self.otp_button.text = "Sign Up"

    def otp_back_arrow_fun(self):
        if self.otp_button.text == "Sign Up":
            self.root.current = 'signup'
        elif self.otp_button.text == "Reset Password":
            self.root.current = 'reset_pass'
        elif self.otp_button.text == "Verify OTP":
            self.root.current = 'borrow_book'

############################################@DIALOG BOX most used functions##############################################
        # MDDialog box function 'dialog'

    def dialog1(self, text, title="Tips"):
        close_button = MDFlatButton(
        text="关闭",
        font_name="MPoppins",
        on_release=self.close_dialog
    )
        
        content_label = Label(
            text=text,
            font_name="MPoppins",
            color=(0, 0, 0, 1),
            size_hint_y=None,
            height=dp(30),
            halign="center",
            valign="middle"
        )
        content_label.bind(size=content_label.setter('text_size'))

        self.dialog = MDDialog(
            title=title,
            type="custom",
            content_cls=content_label,
            size_hint=(0.84, None),
            buttons=[close_button]
        )
        self.dialog.open()
    def dialog2(self, title, text):
        close_button = MDFlatButton(
        text="关闭",
        font_name="MPoppins",
        on_release=self.close_dialog
    )
        
        content_label = Label(
            text=text,
            font_name="MPoppins",
            color=(0, 0, 0, 1),
            size_hint_y=None,
            height=dp(30),
            halign="center",
            valign="middle"
        )
        content_label.bind(size=content_label.setter('text_size'))

        self.dialog = MDDialog(
            title=title,
            type="custom",
            content_cls=content_label,
            size_hint=(0.84, None),
            buttons=[close_button]
        )
        self.dialog.open()



    # MDDialog box dismiss function 'close_dialog'
    def close_dialog(self, *args):
        self.dialog.dismiss()



#############################################Modbus Functions############################################################
    def show_modify_dialog(self, label_id, current_value=""):
        """显示修改对话框"""
        if not self.dialog2:
            # 创建输入框
            self.modify_input = MDTextField(
                id="modify_input",
                hint_text="请输入新值",
                input_filter="int",  # 保持整数输入限制
                text=current_value
            )

            # 创建对话框
            self.dialog2 = MDDialog(
                title="修改参数",
                type="custom",
                content_cls=MDBoxLayout(
                    self.modify_input,
                    orientation="vertical",
                    padding=dp(10),
                    spacing=dp(10),
                    size_hint_y=None,
                    height=dp(100)
                ),
                buttons=[
                    MDFlatButton(
                        text="取消",
                        on_press=lambda x: self.dialog2.dismiss()
                    ),
                    MDFlatButton(
                        text="确认",
                        on_press=lambda x: self.confirm_modify(label_id)
                    )
                ]
            )
        else:
            # 重置输入框内容
            self.modify_input.text = current_value
        
        self.dialog2.open()

    def confirm_modify(self, label_id):
        """确认修改并更新标签"""
        new_value = self.modify_input.text
        if new_value:  # 确保输入不为空
            # 根据标签ID获取对应的标签并更新
            screen = self.root.get_screen("real_time_curve")
            if label_id == "register_label" and hasattr(screen.ids, label_id):
                screen.ids[label_id].text = f"通信超时: {new_value}"  # 更新标签显示
                self.modify_register(new_value)  # 调用原有的修改方法
        self.dialog2.dismiss()  # 关闭对话框

    def read_modbus_registers(self, slave_id, address, count):
        """
        通用的Modbus保持寄存器读取函数
        :param slave_id: 从机ID（动态传入，如1、2、3等）
        :param address: 寄存器地址
        :param count: 读取的寄存器数量
        :return: 读取结果或None（失败时）
        """
        if not self.modbus_master:
            print("Modbus未初始化，请先连接")
            return None
        
        try:
            # 动态传入slave_id，替代固定的1
            result = self.modbus_master.execute(
                slave=slave_id,
                function_code=cst.READ_HOLDING_REGISTERS,
                starting_address=address,
                quantity_of_x=count
            )
            print(f"从机ID {slave_id} 读取成功：{result}")
            if result:
                register_value = result[0]  # 提取元组中的第一个元素（即0）
                print(f"寄存器值：{register_value}")
            return result
        except Exception as e:
            print(f"从机ID {slave_id} 读取失败：{e}")
            return None

    def update_register_display(self, dt):
        """定时更新寄存器值显示"""
        register_value = self.read_modbus_registers(slave_id=1, address=0, count=1)

        # 获取显示标签并更新文本
        real_time_screen = self.root.get_screen("real_time_curve")  # 根据实际屏幕名称调整
        if hasattr(real_time_screen.ids, 'register_label'):

            if register_value is not None:
                real_time_screen.ids.register_label.text = f"寄存器 0: {register_value[0]}"
            else:
                real_time_screen.ids.register_label.text = "寄存器 0: 读取失败或超时"

###################################LoginPageWork-Start#################################################

    def update_wifi_status(self, dt):
        self.check_wifi()
        Clock.schedule_once(self.update_wifi_status, 1)  # 1秒刷新一次

    def check_wifi(self):
        if platform != 'android':
                login_screen = self.root.get_screen("login")  # 根据实际屏幕名称调整
                if hasattr(login_screen.ids, 'wifi_status_text'):
                    self.wifi_status_text = '非Android设备'
                return

        try:
            from jnius import autoclass, cast

            PythonActivity = autoclass('org.kivy.android.PythonActivity')
            Context = autoclass('android.content.Context')
            activity = PythonActivity.mActivity

            WifiManager = autoclass('android.net.wifi.WifiManager')
            Formatter = autoclass('android.text.format.Formatter')

            wifi_service = activity.getSystemService(Context.WIFI_SERVICE)
            wifi_manager = cast('android.net.wifi.WifiManager', wifi_service)

            if not wifi_manager.isWifiEnabled():
                self.wifi_status_text = 'WiFi 未启用'
                return  # 这里直接返回，不再继续取SSID等信息

            wifi_info = wifi_manager.getConnectionInfo()
            if wifi_info is None:
                self.wifi_status_text = 'WiFi 信息不可用'
                return

            ssid = wifi_info.getSSID()
            if ssid:
                ssid_display = ssid.strip('"')
            else:
                ssid_display = "SSID Unknown"

            ip_int = wifi_info.getIpAddress()
            ip_str = Formatter.formatIpAddress(ip_int) if ip_int != 0 else "0.0.0.0"
            link_speed = wifi_info.getLinkSpeed()  # Mbps
            bssid = wifi_info.getBSSID()
            rssi = wifi_info.getRssi()

            self.wifi_status_text = (
                f'SSID: {ssid_display}\n'
                f'IP: {ip_str}\n'
                f'速度: {link_speed} Mbps\n'
                f'BSSID: {bssid}\n'
                f'信号: {rssi} dBm'
            )

        except Exception as e:
            self.wifi_status_text = f'获取WiFi信息失败\n{e}'

    def verify(self, obj=None):
        try:
            if platform == "android":
                from jnius import autoclass
                PythonActivity = autoclass('org.kivy.android.PythonActivity')
                Context = autoclass('android.content.Context')
                activity = PythonActivity.mActivity
                wifi_service = activity.getSystemService(Context.WIFI_SERVICE)
                wifi_info = wifi_service.getConnectionInfo()
                wifi_id = wifi_info.getSSID().strip('"').lower()
            else:
                wifi_id = "zhizhan-2"  # 非 Android 用模拟 WiFi
        except Exception as e:
            self.dialog1(f"获取WiFi信息失败:{e}")
            return

        try:
            with open("data/Users.csv", "r", encoding="utf-8") as file:
                csv_reader = csv.reader(file)
                for line in csv_reader:

                    if len(line) < 8:
                        continue

                    # 假设SSID存储在第8列(索引7)
                    csv_ssid = line[7].strip().lower()

                    # 更精确匹配SSID，且忽略大小写
                    if wifi_id == csv_ssid or wifi_id in map(str.lower, line):
                        name, prn, email, number, password, branch, semester,csv_ssid = line[:8]

                        self.root.current = "home"
                        self.user.text = f"[b]Hey! {name}[/b]"
                        self.profile_name.text = self.edit_name.text = name
                        self.profile_email.text = self.edit_email.text = email
                        self.profile_prn.text = self.edit_prn.text = prn
                        self.profile_number.text = self.edit_number.text = number
                        self.profile_semester.text = self.edit_semester.text = semester
                        self.profile_branch.text = self.edit_branch.text = branch

                        self.connect_modbus()
                        self.dialog1(f"欢迎你，{name}!\n认证成功!")
                        
                        return
        except Exception as e:
            self.dialog1(f"读取用户信息失败：{e}")
            return

        self.dialog1("认证失败,请检查网络或确保手机权限打开定位和连接到目标WiFi")
    # 添加Modbus连接函数
    def connect_modbus(self):
        try:
            # 从CSV文件读取Modbus配置
            modbus_ip = None
            modbus_port = 502  # 默认端口
            
            # 获取当前连接的WiFi SSID
            if platform == "android":
                from jnius import autoclass
                PythonActivity = autoclass('org.kivy.android.PythonActivity')
                Context = autoclass('android.content.Context')
                activity = PythonActivity.mActivity
                wifi_service = activity.getSystemService(Context.WIFI_SERVICE)
                wifi_info = wifi_service.getConnectionInfo()
                current_wifi_id = wifi_info.getSSID().strip('"').lower()
            else:
                current_wifi_id = "zhizhan-2"  # 非Android环境模拟WiFi
                
            # 读取CSV文件查找匹配的Modbus配置
            with open("data/Users.csv", "r", encoding="utf-8") as file:
                csv_reader = csv.reader(file)
                headers = next(csv_reader)  # 获取表头
                
                for line in csv_reader:
                    if len(line) < 10:  # 确保有足够的字段
                        continue
                        
                    # 匹配当前连接的WiFi SSID
                    csv_ssid = line[7].strip().lower()
                    if current_wifi_id == csv_ssid or current_wifi_id in map(str.lower, line):
                        modbus_ip = line[8]
                        modbus_port = int(line[9]) if line[9] else 502
                        break  # 找到匹配项则退出循环
            
            if not modbus_ip:
                # self.dialog1("未找到与当前WiFi匹配的Modbus配置")
                return

            # 断开现有连接（如果存在）
            if hasattr(self, 'modbus_master') and self.modbus_master:
                self.modbus_master.close()

            # 创建新连接
            self.modbus_master = TcpMaster(host=modbus_ip, port=modbus_port)
            self.modbus_master.set_timeout(5.0)  # 设置超时时间
            
            # 测试连接（读取一个保持寄存器）
            self.modbus_master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 1)
            print(f"Modbus连接成功\nIP: {modbus_ip}\n端口: {modbus_port}")
            
        except FileNotFoundError:
            self.dialog1("配置文件user.csv未找到")
        except socket.error as e:
            self.dialog1(f"Modbus连接失败: 网络错误\n{e}")
            self.modbus_master = None
        except Exception as e:
            self.dialog1(f"Modbus连接失败: {e}")
            self.modbus_master = None


###############################################SIGNUP Page Functions#####################################################

    # signup Verification function "check_signup"
    def check_signup(self, name, prn, email, num, password, branch, sem, ssid, modbus_ip, modbus_port):
        if name == "" or prn == "" or email == "" or num == "" or password == "" or branch == "" or sem == "":
            check = "Enter all required fields"
            return self.dialog1(check)
        else:
            status = "None"
            with open('data/Users.csv', "r") as file:
                csv_reader = csv.reader(file, delimiter=',')
                for line in csv_reader:
                    try:
                        if line[3] == num:
                            status = "num"
                            break
                        if line[1] == prn:
                            status = "prn"
                            break
                        if line[2] == email:
                            status = "email"
                            break
                        else:
                            status = False
                    except IndexError:
                        pass
            if status == "num":
                check = "Number already registered Please enter a new number"
                return self.dialog1(check)
            elif status == "prn":
                check = "PRN already registered Please enter a PRN"
                return self.dialog1(check)
            elif status == "email":
                check = "Email already registered Please enter a new email"
                return self.dialog1(check)
            else:
                self.root.current = "otp"
                self.send_otp(num)
                # 保存注册信息时包含Modbus信息
                self.signup_modbus_ip = modbus_ip
                self.signup_modbus_port = modbus_port
                check = "One Time Password has been shared on your registered Whatsapp No. Successful!."
            self.dialog1(check)

##################################################FORGOT PassWord Page##################################################

    # FORGOT PASSWORD page mobile number verification function 'verify_no'
    def verify_no(self):
        status = False
        if self.mobile_no.text == "":
            check = "Please enter your Mobile Number."
            return self.dialog1(check)
        else:
            with open('data/Users.csv', "r", encoding="utf-8") as file:
                csv_reader = csv.reader(file, delimiter=",")
                for line in csv_reader:
                    try:
                        if line[3] == self.mobile_no.text:
                            status = True
                            break
                        else:
                            status = False
                    except IndexError:
                        pass
                    except Exception as e:
                        print(e)

        if status:
            check = "One Time Password has been shared on your registered Whatsapp No. Successful!."
            self.root.current = "otp"
            self.send_otp(self.mobile_no.text)
            return self.dialog1(check)
        else:
            check = "Enter Registered Mobile Number."
        self.dialog1(check)

    def reset_password(self):
        if self.new_pass.text == "" or self.new_pass1.text == "":
            check = "Please enter your new password"
            return self.dialog1(check)

        elif not self.new_pass.text == self.new_pass1.text:
            check = "Password Does Not Match. \nPlease Re-check your password."
            return self.dialog1(check)

        else:
            with open('data/Users.csv', "r", encoding="utf-8") as file:
                csv_reader = csv.DictReader(file, delimiter=",")
                rows = [row for row in csv_reader]

            for row in rows:
                if row['Student_Whatsapp_no'] == self.mobile_no.text:
                    row['Student_pass'] = self.new_pass.text
                    break

            try:
                with open('data/Users.csv', "w", newline='', encoding="utf-8") as file:
                    headers = ["Student_Name", "Student_PRN", "Student_Email", "Student_Whatsapp_no", "Student_pass",
                               "Branch", "Semester"]
                    csv_writer = csv.DictWriter(file, fieldnames=headers)
                    csv_writer.writeheader()
                    csv_writer.writerows(rows)
                check = "Password Updated Successfully!"
                self.root.current = "login"
            except Exception as e:
                print(e)
                check = "Something went wrong please try again."
        self.dialog1(check)

###############################################PROFILE & EDIT Profile Page##############################################

    def edit_profile(self):
        if self.edit_name.text == "" or self.edit_prn.text == "" or self.edit_email.text == "" or self.edit_number.text == "":
            check = "Enter all required fields"
            return self.dialog1(check)
        else:
            with open('data/Users.csv', "r", encoding="utf-8") as file:
                csv_reader = csv.DictReader(file, delimiter=",")
                rows = [row for row in csv_reader]

            for row in rows:
                if row['Student_Whatsapp_no'] == self.profile_number.text:
                    row['Student_Name'] = self.edit_name.text
                    row['Student_PRN'] = self.edit_prn.text
                    row['Student_Email'] = self.edit_email.text
                    row['Student_Whatsapp_no'] = self.edit_number.text
                    row['Student_pass'] = self.password.text
                    row['Branch'] = self.edit_branch.text
                    row['Semester'] = self.edit_semester.text
                    break

            with open('data/Users.csv', newline="", mode="w", encoding="utf-8") as file:
                header = ["Student_Name", "Student_PRN", "Student_Email", "Student_Whatsapp_no", "Student_pass",
                          "Branch", "Semester"]
                csv_writer = csv.DictWriter(file, fieldnames=header)
                csv_writer.writeheader()
                csv_writer.writerows(rows)
            self.verify(True)
            self.root.current = "home"

    def secure_profile(self):
        self.profile_edit_screen.ids.edit_email.readonly = True
        self.profile_edit_screen.ids.edit_prn.readonly = True
        self.profile_edit_screen.ids.edit_no.readonly = True
        self.profile_edit_screen.ids.edit_private_credential_butn.disabled = False


#############################################OTP SEND & VERIFY PAGE#####################################################

    def send_otp(self, number):
        self.a = random.randint(1000, 9999)
        if len(str(number)) == 10:
            number1 = "+91" + str(number)
            message = f"""Your verification code is {self.a}. It expires in 10 minutes. Don’t share this code with anyone."""
            pywhatkit.sendwhatmsg_instantly(number1, message, wait_time=15, tab_close=True, close_time=3)
        elif len(str(number)) != 10:
            check = "Please enter a 10 digit number."
            return self.dialog1(check)
        else:
            pass

    def verify_otp(self, d1, d2, d3, d4, otp_button):
        entered_otp = str(d1) + str(d2) + str(d3) + str(d4)
        if entered_otp == str(self.a):
            if otp_button == "Reset Password":
                self.root.current = "reset_pass"
                check = "Reset your password "
                return self.dialog1(check)

            elif otp_button == "Edit Credentials":
                self.root.current = "profile_edit"
                check = "Edit your credentials "
                self.profile_edit_screen.ids.edit_email.readonly = False
                self.profile_edit_screen.ids.edit_prn.readonly = False
                self.profile_edit_screen.ids.edit_no.readonly = False
                self.profile_edit_screen.ids.edit_private_credential_butn.disabled = True
                return self.dialog1(check)

            elif otp_button == "Verify OTP":
                self.root.current = "home"
                self.add_book()

            else:
                data = [self.user_name.text, self.user_prn.text, self.user_email.text, self.user_no.text,
                        self.user_pass.text, self.signup_branch.text, self.signup_sem.text]

                with open('data/Users.csv', encoding="utf-8") as file:
                    csv_writer = csv.writer(file, delimiter=",")
                    csv_writer.writerow(data)

                self.root.current = "home"
                check = "SignUP Successful" + "\nHello ! " + self.user_name.text
                self.user.text = "H e y  !" + self.user_name.text
                self.verify(True)
                return self.dialog1(check)

        elif entered_otp != str(self.a):
            check = "Please enter a correct verification code."
            self.d1.text = ""
            self.d2.text = ""
            self.d3.text = ""
            self.d4.text = ""
            return self.dialog1(check)

        else:
            check = "Sorry! Try again later."
            self.root.current = "login"
            self.d1.text = ""
            self.d2.text = ""
            self.d3.text = ""
            self.d4.text = ""
            return self.dialog1(check)

    #######################################################Borrow BOok######################################################

    def get_book(self, isbn):
        self.isbn.text = isbn
        if not self.isbn.text:
            check = "Please enter a valid ISBN."
            return self.dialog1(check)
        elif not len(self.isbn.text) == 13:
            check = "Please enter a valid ISBN."
            return self.dialog1(check)
        else:
            with open('data/Books.csv', mode="r", encoding="utf-8") as file:
                csv_reader = csv.DictReader(file, delimiter=",")
                rows = [row for row in csv_reader]
            for row in rows:
                if row["ISBN"] == self.isbn.text:
                    if row['Availability'] == "0":
                        check = "Your book is unavailable. "
                        return self.dialog1(check)
                    else:
                        self.otp_button_fun('2')
                        self.root.current = "otp"
                        self.send_otp(self.profile_number.text, )

    def add_book(self):
        with open('data/Books.csv', mode="r", encoding="utf-8") as file:
            csv_reader = csv.DictReader(file, delimiter=",")
            rows = [row for row in csv_reader]

        for row in rows:
            if row['ISBN'] == self.isbn.text:
                try:
                    self.book_name = row['Name']
                    a = row['Availability']
                    row['Availability'] = str(int(a) - 1)
                except KeyError:
                    pass

        with open('data/Books.csv', newline="", mode="w", encoding="utf-8") as file:
            headers = ["Name", "Author", "Publication Year", "Publisher", "ISBN",
                       "Availability"]
            csv_writer = csv.DictWriter(file, fieldnames=headers)
            csv_writer.writeheader()
            csv_writer.writerows(rows)

        self.date = datetime.now()
        self.Due_date = self.date + timedelta(days=10)

        details = [self.profile_prn.text, self.profile_number.text, self.book_name, self.isbn.text, self.date,
                   self.Due_date, ]
        transaction_details = details + ["Not Returned"]
        borrow_details = details + ["Not Renewed"]

        files = ['data/borrowed_books.csv', 'data/all_book_transactions.csv']
        for file1 in files:
            with open(file1, "a", encoding="utf-8", newline='') as file:
                csv_writer = csv.writer(file, delimiter=",")
                if file1 == 'data/borrowed_books.csv':
                    csv_writer.writerow(borrow_details)
                elif file1 == 'data/all_book_transactions.csv':
                    csv_writer.writerow(transaction_details)

        check = "OTP Verified! \nBook Borrowed Successfully!"
        return self.dialog1(check)

    def fetch_borrowed_book(self):
        with open('data/borrowed_books.csv', mode="r", encoding="utf-8") as file:
            csv_reader = csv.DictReader(file, delimiter=",")
            rows = [row for row in csv_reader]
        self.books.clear()
        for row in rows:
            if row['User'] == self.profile_prn.text:
                book = {'source': 'assets/sample_book_display.jpg', 'btn_text': 'Return Book', 'Book_name': row['Book_Name'],
                        'time': row['Due_Date'], 'Renew_status': row['Renew_status']}
                self.books += [book]
                print(self.books)
        self.items = self.books

    def fetch_renewable_books(self):
        with open('data/borrowed_books.csv', mode="r", encoding="utf-8") as file:
            csv_reader = csv.DictReader(file, delimiter=",")
            rows = [row for row in csv_reader]
        self.renewable_books.clear()
        for row in rows:
            a = datetime.strptime(row['Due_Date'], "%Y-%m-%d %H:%M:%S.%f")
            a = a.strftime("%d-%m-%Y")
            if row['User'] == self.profile_prn.text and row[
                'Renew_status'] == "Not Renewed" and a == datetime.now().strftime("%d-%m-%Y"):
                renew_book = {'source': 'assets/sample_book_display.jpg', 'btn_text': 'Renew Book', 'Book_name': row['Book_Name'],
                              'time': row['Due_Date'], 'Renew_status': row['Renew_status']}
                self.renewable_books += [renew_book]
                print(self.renewable_books)
            self.renew = self.renewable_books

    def return_book(self, obj):
        if obj == 'Return':
            self.fetch_borrowed_book()
            self.image_label_grid.clear_widgets()
            book_list = self.items
        elif obj == 'Renew':
            self.fetch_renewable_books()
            self.renew_grid.clear_widgets()
            book_list = self.renew

        for item in book_list:
            box = MDBoxLayout(orientation='vertical', size_hint_y=None, height="125dp")
            anchor = AnchorLayout(anchor_x="center", anchor_y="center")
            grid = GridLayout(cols=2, spacing=dp(20), size_hint_x=None, size_hint_y=None, size=[dp(320), dp(200)],
                              padding=dp(0))

            img = Image(source=item['source'],
                        size_hint_x=None,
                        size_hint_y=None,
                        width=dp(100),
                        height=dp(125),
                        allow_stretch=True)
            label = MDLabel(
                text=item['Book_name'],
                font_name="BPoppins",
                size_hint_x=None,
                size_hint_y=None,
                bold=True,
                size=[dp(215), dp(70)],
                padding=dp(0),
                on_touch_down=lambda instance, touch: self.change_cursor(True),
                on_touch_up=lambda instance, touch: self.change_cursor(False),
            )
            date11 = item['time']
            date22 = "Due Date is "
            for i in range(10):
                date22 += date11[i]

            label1 = MDLabel(
                text=date22,
                font_name="BPoppins",
                size_hint_x=None,
                size_hint_y=None,
                size=[dp(215), dp(40)],
                padding=dp(0),
                on_touch_down=lambda instance, touch: self.change_cursor(True),
                on_touch_up=lambda instance, touch: self.change_cursor(False),
            )

            if item['btn_text'] == "Return Book":
                btn = Button(
                    text=item['btn_text'],
                    font_name="BPoppins",
                    size_hint=(None, None),
                    size=(dp(200), dp(30)),
                    background_color=(0, 0, 1, 1),
                    on_touch_down=lambda instance, touch: self.change_cursor(True),
                    on_touch_up=lambda instance, touch: self.change_cursor(False),
                    on_release=lambda instance, src=item['source'], txt=item['btn_text'], name=item['Book_name'],
                                      time=item['time']: self.remove_book(src, txt, name, time),
                )
            elif item['btn_text'] == "Renew Book":
                btn = Button(
                    text=item['btn_text'],
                    font_name="BPoppins",
                    size_hint=(None, None),
                    size=(dp(200), dp(30)),
                    background_color=(0, 0, 1, 1),
                    on_touch_down=lambda instance, touch: self.change_cursor(True),
                    on_touch_up=lambda instance, touch: self.change_cursor(False),
                    on_release=lambda instance, src=item['source'], txt=item['btn_text'], name=item['Book_name'],
                                      time=item['time']: self.renew_book(src, txt, name, time),
                )

            vertical_box = BoxLayout(orientation='vertical', size_hint_y=None, height=label.height + btn.height)
            vertical_box.add_widget(label)
            vertical_box.add_widget(label1)
            vertical_box.add_widget(btn)

            grid.add_widget(img)
            grid.add_widget(vertical_box)
            anchor.add_widget(grid)
            box.add_widget(anchor)
            if btn.text == "Return Book":
                self.image_label_grid.add_widget(box)
            elif btn.text == "Renew Book":
                self.renew_grid.add_widget(box)

    def remove_book(self, source, text, name, time):
        with open('data/borrowed_books.csv', mode="r", encoding="utf-8") as file:
            csv_reader = csv.reader(file, delimiter=",")
            header = next(csv_reader)
            rows = list(csv_reader)

        new_rows = [row for row in rows if row[0] != self.profile_prn.text or row[2] != name or row[5] != time]

        with open('data/borrowed_books.csv', mode="w", newline="", encoding="utf-8") as file:
            csv_writer = csv.writer(file, delimiter=",")
            csv_writer.writerow(header)
            csv_writer.writerows(new_rows)

        with open('data/all_book_transactions.csv', mode="r", encoding="utf-8") as file:
            csv_reader = csv.DictReader(file, delimiter=",")
            rows = [row for row in csv_reader]

        return_date = datetime.now()
        return_date = return_date.strftime("%d/%m/%Y")

        for row in rows:
            if row['User'] == self.profile_prn.text and row['Book_Name'] == name and row['Due_Date'] == time:
                row["Return_Date"] = return_date

        with open('data/all_book_transactions.csv', mode="w", newline="", encoding="utf-8") as file:
            headers = ['User', 'User_No', 'Book_Name', 'ISBN', 'Date', 'Due_Date', 'Return_Date', ]
            csv_writer = csv.DictWriter(file, fieldnames=headers)
            csv_writer.writeheader()
            csv_writer.writerows(rows)

        with open('data/Books.csv', mode="r", encoding="utf-8") as file:
            csv_reader = csv.DictReader(file, delimiter=",")
            rows = [row for row in csv_reader]

        for row in rows:
            if row['Name'] == name:
                try:
                    a = row['Availability']
                    row['Availability'] = str(int(a) + 1)
                except KeyError:
                    pass

        with open('data/Books.csv', newline="", mode="w", encoding="utf-8") as file:
            headers = ["Name", "Author", "Publication Year", "Publisher", "ISBN",
                       "Availability"]
            csv_writer = csv.DictWriter(file, fieldnames=headers)
            csv_writer.writeheader()
            csv_writer.writerows(rows)

        self.items = [item for item in self.items if
                      not (item['source'] == source and item['btn_text'] == text and item['Book_name'] == name)]

        check = "Book Returned Successfully!"
        self.dialog1(check)
        self.return_book("Return")

    def fetch_book_history(self):
        with open('data/all_book_transactions.csv', mode="r", encoding="utf-8") as file:
            csv_reader = csv.DictReader(file, delimiter=",")
            rows = [row for row in csv_reader]
        self.books_history.clear()
        for row in rows:
            if row['User'] == self.profile_prn.text and row['Return_Date'] != 'Not Returned':
                book = {'source': 'assets/sample_book_display.jpg', 'text': 'Rate Book', 'Book_name': row['Book_Name'],
                        'time': row['Date'], 'Return_Date': row['Return_Date']}
                self.books_history += [book]
        self.history = self.books_history

    def book_history(self):
        self.fetch_book_history()
        self.history_grid.clear_widgets()

        for item in self.history:
            box = MDBoxLayout(orientation='vertical', size_hint_y=None, height="125.001dp")
            anchor = AnchorLayout(anchor_x="center", anchor_y="center")
            grid = GridLayout(cols=2, spacing=dp(20), size_hint_x=None, size_hint_y=None, size=[dp(320), dp(200)],
                              padding=dp(0))

            img = Image(source=item['source'], size_hint_x=None, size_hint_y=None, width=dp(100), height=dp(125),
                        allow_stretch=True)
            label = MDLabel(
                text=item['Book_name'],
                font_name="BPoppins",
                size_hint_x=None,
                size_hint_y=None,
                bold=True,
                size=[dp(215), dp(60)],
                padding=dp(0),
                on_touch_down=lambda instance, touch: self.change_cursor(True),
                on_touch_up=lambda instance, touch: self.change_cursor(False),
            )

            B_date = datetime.strptime(item['time'], '%Y-%m-%d %H:%M:%S.%f')
            B_date = B_date.strftime("%d-%m-%Y")

            formated_B = ""
            for i in range(10):
                formated_B += B_date[i]

            R_date = datetime.strptime(item['Return_Date'], '%d/%m/%Y')
            R_date = R_date.strftime("%d-%m-%Y")
            formated_R = ""
            for i in range(10):
                formated_R += R_date[i]

            date22 = f"""Borrow Date: {formated_B}\nReturn Date: {formated_R}"""

            label1 = MDLabel(
                text=date22,
                font_name="BPoppins",
                size_hint_x=None,
                size_hint_y=None,
                size=[dp(215), dp(50)],
                padding=dp(0),
                on_touch_down=lambda instance, touch: self.change_cursor(True),
                on_touch_up=lambda instance, touch: self.change_cursor(False),
            )

            btn = Button(
                text=item['text'],
                font_name="BPoppins",
                size_hint=(None, None),
                size=(dp(200), dp(30)),
                background_color=(0, 0, 1, 1),
                on_touch_down=lambda instance, touch: self.change_cursor(True),
                on_touch_up=lambda instance, touch: self.change_cursor(False),
            )
            vertical_box = BoxLayout(orientation='vertical', size_hint_y=None, height=label.height + btn.height)
            vertical_box.add_widget(label)
            vertical_box.add_widget(label1)
            vertical_box.add_widget(btn)

            grid.add_widget(img)
            grid.add_widget(vertical_box)
            anchor.add_widget(grid)
            box.add_widget(anchor)
            self.history_grid.add_widget(box)

    def data_load(self):
        self.search_field.bind(text=self.search_books)
        self.search_grid.clear_widgets()
        self.data_tables = MDDataTable(
            pos_hint={'center_x': 0.5, 'center_y': 0.4},
            size_hint=(0.95, 0.5),
            use_pagination=True,
            padding=dp(0),
            rows_num=7,
            pagination_menu_pos='auto',
            background_color_selected_cell=(0.8, 0.9, 1, 1),
            column_data=[
                ("Book Name", dp(80)),
                ("Author", dp(50)),
                ("Publication Year", dp(30)),
                ("Publisher", dp(40)),
                ("ISBN", dp(30)),
                ("Availability", dp(30)),
            ],
            row_data=get_books()
        )
        self.search_grid.add_widget(self.data_tables)

    def search_books(self, instance, value):
        all_data = get_books()
        filtered_data = [row for row in all_data if (
                    value.lower() in row[0].lower() or value.lower() in row[1].lower() or value.lower() in row[4])]
        self.data_tables.row_data = filtered_data

    def get_recommendations(self):
        book_title = self.book_input.text
        recommendations = self.rec_book(book_title)
        if isinstance(recommendations, str):
            self.rec_label.text = recommendations
            self.rec_grid.clear_widgets()
        else:
            self.display_rec_table(recommendations)

    @staticmethod
    def rec_book(book_title):
        book_title_lower = book_title.lower()
        if book_title_lower not in df["Name_lower"].values:
            return f"{book_title} not in database"
        index = df[df['Name_lower'] == book_title_lower].index[0]

        distance, indices = knn.kneighbors(s_matrix[index].reshape(1, -1))
        rec_title = df.iloc[indices.flatten()]["Name"].tolist()
        aval = df.iloc[indices.flatten()]["Availability"].tolist()
        isbn = df.iloc[indices.flatten()]["ISBN"].tolist()

        recommendation = list(zip(rec_title, isbn, aval))

        return recommendation

    def display_rec_table(self, recommendations):
        self.rec_grid.clear_widgets()
        data_tables = MDDataTable(
            pos_hint={'center_x': 0.5, 'center_y': 0.2},
            size_hint=(0.95, 0.2),
            use_pagination=True,
            padding=dp(0),
            rows_num=6,
            pagination_menu_pos='auto',
            background_color_selected_cell=(0.8, 0.9, 1, 1),
            column_data=[
                ("Book Name", dp(80)),
                ("ISBN", dp(30)),
                ("Availability", dp(30)),
            ],
            row_data=[(title, isbn, availability) for title, isbn, availability in recommendations]
        )
        self.rec_grid.add_widget(data_tables)

    def where_is_book(self):
        with open('data/book_positions.csv', 'r') as csvfile:
            data = csv.reader(csvfile, delimiter=',')
            rows = list(data)
            a = self.book_pos_name.text.lower()
            for row in rows:
                if row[0].lower() == a:
                    pos = str(row[1])
                    self.book_pos.text = f"{a.upper()} Book is kept at {row[1]} location. Please Go and Borrow it!!\n({row[1]} means {pos[0]} th row, Left/Right side(L/R), {pos[2]} th shelf, {pos[3]} th shelf step )"
                    break
                else:
                    self.book_pos.text = "Please check the Spell!"


if __name__ == '__main__':
    app().run()



