#--------------------------------------------------------
# KZライブラリ  庇屋根小屋組み
#               2025/02/03
#               written by Fukurou
# 当スクリプトについてライセンス条項　MIT License　を適用いたします。
#--------------------------------------------------------
import bpy
import gpu
import copy
import math
import mathutils
import numpy as np
import pathlib

from math import radians
from mathutils import Vector
from mathutils import Matrix
from bpy.types import Operator
from bpy.props import *
from bpy_extras import view3d_utils
from gpu_extras.batch import batch_for_shader
from .module import kzb_mod_base
from .module import kzb_mod_unit
from .module import kzb_mod_frame
from .module import kzb_cmp_roof
#from .module import kzb_cmp_katanagare
from . import kzb_std_base

#-----------------------------------------------------------
# 小屋組み
#-----------------------------------------------------------
class KZBTOOLS_OT_SEC_HisasiyaneInput(bpy.types.Operator):
    bl_idname = 'kzb_sec.hisasiyaneinput'
    bl_label  = '庇屋根'
    bl_description = 'パラメータ入力'

    koubai: EnumProperty(
        name="屋根勾配",
        description="勾配を指定",
        default='3',
        items=[
            ('1', "1寸勾配", "5.7度"),
            ('2', "2寸勾配", "11.3度"),
            ('3', "3寸勾配", "16.7度"),
            ('4', "4寸勾配", "21.8度"),
            ('5', "5寸勾配", "26.5度"),
            ('6', "6寸勾配", "30.9度"),
            ('7', "7寸勾配", "34.9度"),
            ('8', "8寸勾配", "39.6度"),
            ('9', "9寸勾配", "42.0度"),
        ]
    )
    level: FloatProperty(       #ブロック用
        name="基点",
        description="壁の高さ",
        default = 0,
        precision=3,
    )
    height: FloatProperty(       #ブロック用
        name="設置高さ",
        description="壁の高さ",
        default = 3,
        precision=3,
    )
    
    def execute(self, context):
        KZBTOOLS_OT_SecsetHisasiyane.level   = self.level
        KZBTOOLS_OT_SecsetHisasiyane.height  = self.height
        KZBTOOLS_OT_SecsetHisasiyane.koubai  = self.koubai
        KZBTOOLS_OT_SecdlgHisasiyane.clevel  = self.level
        KZBTOOLS_OT_SecdlgHisasiyane.cheight = self.height
        KZBTOOLS_OT_SecdlgHisasiyane.ckoubai = self.koubai
        bpy.ops.kzb_set.sechisasiyane('INVOKE_DEFAULT')
        return {'FINISHED'}
        
    def invoke(self, context, event):
        # カスタムプロパティ
        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):
        layout = self.layout
        #コレクション表示
        kzb_std_base.disp_collection(context, layout)
        #base
        box = layout.box()
        col = box.column()
        col.use_property_split = True   #メニューを分割表示
        col.label(text="配置オプション")
        col.prop(self, "level")        #基点
        col.prop(self, "height")       #高さ
        col.prop(self, "koubai")       #勾配
        layout.separator()

#-----------------------------------------------------------
# 小屋組み作成クラス
#-----------------------------------------------------------
class KZBTOOLS_OT_SecsetHisasiyane(bpy.types.Operator):
    bl_idname = 'kzb_set.sechisasiyane'
    bl_label  = '庇屋根'
    bl_description = '庇屋根を作成'

    mouse_path = []
    actv = Vector((0,0,0))
    level  = 0.0
    height = 3.0
    koubai = '3'
    kakudo = 30
    #モーダル
    def modal(self, context, event):
        props = context.scene.myproperty
        context.area.tag_redraw()
        #マウス座標
        mx = event.mouse_region_x
        my = event.mouse_region_y
        n = len(self.mouse_path)
        #座標変換
        self.actv = kzb_mod_base.convert_gridpos(context, mx, my, props.kz_snap)
        if self.actv == None:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            self.mouse_path.clear()
            return {'CANCELLED'}
        if event.type == 'LEFTMOUSE': #左クリック
            if event.value == 'PRESS':
                #点を登録する
                self.mouse_path.append(self.actv)
                n = len(self.mouse_path)
                #完了
                if n == 3:
                    bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
                    #ダイアログクラス呼出
                    KZBTOOLS_OT_SecdlgHisasiyane.kz_path = self.mouse_path
                    #self.mouse_path.clear()
                    bpy.ops.kzb_dialog.sechisasiyane('INVOKE_DEFAULT')
                    return {'CANCELLED'}
        elif event.type == 'RIGHTMOUSE':   #右クリック/中止
            self.mouse_path.clear()
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}
        elif event.type == 'ESC':           #中止
            self.mouse_path.clear()
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.area.type != 'VIEW_3D':
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}
        args = (self, context)
        self._handle = bpy.types.SpaceView3D.draw_handler_add(kzb_mod_unit.draw_callback_kroof, args, 'WINDOW', 'POST_PIXEL')
        self.mouse_path.clear()
        # 勾配角度
        #rad = kzb_mod_base.convert_koubai(self.koubai)
        self.kakudo = kzb_mod_base.koubai_to_deg(self.koubai)
        #メッセージ
        self.report({'INFO'}, "片流れ屋根・庇屋根：配置位置を指定して下さい（妻面から３箇所）")
        context.window_manager.modal_handler_add(self)
        bpy.context.window.cursor_set("CROSSHAIR")  #(+)カーソル
        return {'RUNNING_MODAL'}

#-----------------------------------------------------------
# ダイアログインプット
#-----------------------------------------------------------
class KZBTOOLS_OT_SecdlgHisasiyane(bpy.types.Operator):
    bl_idname = "kzb_dialog.sechisasiyane"
    bl_label  = "庇屋根・庇屋根"
    bl_options = {'REGISTER', 'UNDO'}
    
    kz_path = []
    #クラス変数
    comp_pos = Vector((0,0,0))
    wspan   = 0.0
    lspan   = 0.0
    clevel  = 0
    cheight = 3.0
    ckoubai = '3'
    width = 0
    length = 0
    #プロパティ
    rstyle: EnumProperty(
        name="形状",
        description="外観形状の種類",
        default='R',
        items=[
            ('S', "シンプル", ""),
            ('R', "レトロ", ""),
        ]
    )
    ktype: EnumProperty(
        name="屋根形状",
        description="",
        default='S',
        items=[
            ('S', "屋根小屋組", "通常の片流れ"),
            ('H', "庇構造屋根", "水上壁接続片流れ形状屋根"),
        ]
    )
    rface: EnumProperty(
        name="屋根材種類",
        description="作成方法を設定します",
        default='F',
        items=[
            ('F', "平屋根", ""),
            ('B', "瓦棒葺", ""),
            ('K', "瓦屋根", ""),
        ]
    )
    koubai: EnumProperty(
        name="屋根勾配",
        description="勾配を指定",
        default='3',
        items=[
            ('1', "1寸勾配", "5.7度"),
            ('2', "2寸勾配", "11.3度"),
            ('3', "3寸勾配", "16.7度"),
            ('4', "4寸勾配", "21.8度"),
            ('5', "5寸勾配", "26.5度"),
            ('6', "6寸勾配", "30.9度"),
            ('7', "7寸勾配", "34.9度"),
            ('8', "8寸勾配", "39.6度"),
            ('9', "9寸勾配", "42.0度"),
        ]
    )
    deg: FloatProperty(       #屋根勾配（角度）
        name="屋根勾配",
        description="角度",
        default = 0,
        precision=1,
    )
    level: FloatProperty(       #ブロック用
        name="設置基点",
        description="基準の高さ",
        default = 0,
        precision=3,
    )
    height: FloatProperty(       #ブロック用
        name="設置高さ",
        description="設置壁の高さ",
        default = 3,
        precision=3,
    )
    hafub: BoolProperty(
        name="破風",
        description="破風を設ける",
        default = True,
    )
    hanab: BoolProperty(
        name="鼻隠し",
        description="鼻隠しを設ける",
        default = False,
    )
    muneb: BoolProperty(
        name="棟包板・棟瓦",
        description="瓦棒葺・瓦屋根の場合",
        default = False,
    )
    doffs: FloatProperty(
        name="奥行きオフセット",
        description = "前後調整",
        default = 0.0,
        precision=3,
    )
    soffs: FloatProperty(
        name="サイドオフセット",
        description = "左右調整",
        default = 0.0,
        precision=3,
    )
    depthr: FloatProperty(
        name="外壁厚",
        description="柱芯からの厚み",
        default = 0.075,
        precision=3,
    )
    tops: FloatProperty(
        name="水上軒の出",
        description="軒先の長さ",
        default = 0.2,
        precision=3,
    )
    toffs: FloatProperty(
        name="水上壁オフセット",
        description="軒先の長さ",
        default = 0.0,
        precision=3,
    )
    nokis: FloatProperty(
        name="軒先長さ",
        description="軒先の長さ",
        default = 0.6,
        precision=3,
    )
    koffs: FloatProperty(
        name="けらば軒の出",
        description="けらば軒の出",
        default = 0.3,
        precision=3,
    )
    hafuw: FloatProperty(
        name="破風巾",
        description="けらば破風巾",
        default = 0.15,
        precision=3,
    )
    hafud: FloatProperty(
        name="破風厚",
        description="けらば破風厚",
        default = 0.02,
        precision=3,
    )
    depth: FloatProperty(
        name="屋根の厚さ",
        description="",
        default = 0.015,
        precision=3,
    )
    fdepth: FloatProperty(
        name="表面板の厚さ",
        description="",
        default = 0.005,
        precision=3,
    )
    tarukw: FloatProperty(
        name="垂木巾",
        description="",
        default = 0.045,
        precision=3,
    )
    tarukd: FloatProperty(
        name="垂木厚（高さ）",
        description="",
        default = 0.06,
        precision=3,
    )
    tpitch: FloatProperty(
        name="垂木間隔",
        description="",
        default = 0.455,
        precision=3,
    )
    taruks: FloatProperty(
        name="垂木オフセット（上）",
        description="",
        default = 0,
        precision=3,
    )
    taruke: FloatProperty(
        name="垂木オフセット（下）",
        description="",
        default = 0.02,
        precision=3,
    )
    nokid: FloatProperty(
        name = "軒桁厚（高さ）",
        description="高さ方向の寸法",
        default = 0.12,
        precision=3,
    )
    nokiw: FloatProperty(
        name = "軒桁巾",
        description="水平方向の寸法",
        default = 0.105,
        precision=3,
    )
    moya: FloatProperty(
        name = "母屋寸法",
        description="角寸法",
        default = 0.11,
        precision=3,
    )
    kbouh: FloatProperty(
        name="瓦棒高さ",
        description="",
        default=0.039,
        precision=3,
    )
    kbouw: FloatProperty(
        name="瓦棒巾",
        description="",
        default=0.043,
        precision=3,
    )
    kboup: FloatProperty(
        name="瓦棒ピッチ",
        description="",
        default=0.418,
        precision=3,
    )
    pitch: FloatProperty(
        name="母屋間隔",
        description = "母屋間隔を変更します",
        default = 0.91,
        precision=3,
    )

    def execute(self, context):
        create_hisasiyane(self, context)    
        return {'FINISHED'}
    
    def invoke(self, context, event):
        self.level  = self.clevel
        self.height = self.cheight
        #self.koubai = self.ckoubai
        self.deg    = kzb_mod_base.koubai_to_deg(self.ckoubai)
        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):
        layout = self.layout
        #コレクション表示
        kzb_std_base.disp_collection(context, layout)
        #base
        box = layout.box()
        col = box.column()
        col.use_property_split = True   #メニューを分割表示
        col.label(text="配置オプション")
        col.prop(self, "rstyle")        #外観形状
        #col.prop(self, "koubai")       #屋根勾配
        col.prop(self, "deg")           #屋根勾配
        col.prop(self, "level")         #設置基準
        col.prop(self, "height")        #設置高さ
        layout.separator()
        #user
        box = layout.box()
        col = box.column()
        col.use_property_split = True
        col.label(text="共通オプション")
        col.prop(self, "tops")          #水上軒の出
        col.prop(self, "nokis")         #軒の出
        col.prop(self, "koffs")         #けらば軒の出
        col.prop(self, "fdepth")        #表面板の厚さ
        #col.prop(self, "depth")         #屋根の厚さ
        #col.prop(self, "moya")          #母屋寸法
        #col.prop(self, "pitch")         #母屋間隔
        #col.prop(self, "tarukw")        #垂木巾
        #col.prop(self, "tarukd")        #垂木厚（高さ
        #col.prop(self, "tpitch")        #垂木間隔
        #col.prop(self, "taruks")        #垂木オフセット（上)
        #col.prop(self, "taruke")        #垂木オフセット（下）
        #col.prop(self, "nokiw")         #軒桁巾
        #col.prop(self, "nokid")         #軒桁厚（高さ）
        col.prop(self, "depthr")        #外壁厚
        col.prop(self, "toffs")         #水上壁オフセット
        col.prop(self, "hafub")         #破風
        if self.hafub:
            col.prop(self, "hafuw")     #破風巾
            col.prop(self, "hafud")     #破風板厚
        col.prop(self, "hanab")         #鼻隠し
 
        #col.prop(self, "lspan")         #棟方向壁長
        #col.prop(self, "wspan")         #妻方向壁長
        #layout.separator()
        #custom
        box = layout.box()
        col = box.column()
        col.use_property_split = True
        col.label(text="形状タイプ")
        col.prop(self, "ktype")         #屋根形状
        col.prop(self, "rface")         #屋根材種類
        if self.rface == 'B':
            col.prop(self, "kbouw")     #瓦棒巾
            col.prop(self, "kbouh")     #瓦棒高さ
            col.prop(self, "kboup")     #瓦棒ピッチ

#-----------------------------------------------------------
# 屋根作成
#-----------------------------------------------------------
def create_hisasiyane(self, context):

    #配置座標
    p1 = self.kz_path[0]
    p2 = self.kz_path[1]
    p3 = self.kz_path[2]
    p4 = p3 + p1 - p2
    self.wspan = (p1 - p2).length       #妻方向壁長
    self.lspan = (p2 - p3).length       #棟方向壁長
    self.comp_pos = (p1 + p3) /2.0      #中央点
    self.width  = self.wspan + self.tops + self.nokis   #屋根巾
    self.length = self.lspan + self.koffs * 2.0         #屋根棟長（+けらば軒の出）
    #角度
    vect = p2 - p1
    rad  = math.atan2(vect[1], vect[0])
    self.kakudo = math.degrees(rad)    
    #縦柱
    height = self.level + self.height - self.nokid
    kzb_mod_frame.create_pillar(p2, self.nokid, height)
    kzb_mod_frame.create_pillar(p3, self.nokid, height)
    if self.ktype == 'S':   # 小屋組み
        kzb_mod_frame.create_pillar(p1, self.nokid, height)
        kzb_mod_frame.create_pillar(p4, self.nokid, height)
    #横柱
    h = self.level + self.height
    s = self.nokid / 2.0
    verts = [p1, p2]
    kzb_mod_frame.create_hpillar('T', verts, h, self.nokid, -s, -s)
    verts = [p4, p3]
    kzb_mod_frame.create_hpillar('T', verts, h, self.nokid, -s, -s)
    #水上桁
    if self.ktype == 'S':   # 小屋組み
        s = self.koffs
        verts = [p1, p4]
        kzb_mod_frame.create_hpillar('T', verts, h, self.nokid, s, s)
    #屋根コンポーネント作成
    make_roof(self, context)

#-------------------------------------------------
# 実行
#-------------------------------------------------
def make_roof(self, context):

    #片流れ用初期化データ
    object = make_hisasiyane(self, context)
    #位置・回転
    object.rotation_euler.rotate_axis('Z', math.radians(self.kakudo+90))
    object.location += self.comp_pos

#-------------------------------------------------
# 実行
#-------------------------------------------------
def make_hisasiyane(self, context):

    #グループ
    group = kzb_mod_base.create_emptyobj("Group_Onesidedroof", 'PLAIN_AXES', 0.5)
    #勾配
    #rad = kzb_mod_base.convert_koubai(self.koubai)
    rad = math.radians(self.deg)
    cs = math.cos(rad)
    tn = math.tan(rad)
    #グループ基点
    pt = Vector((self.soffs, self.doffs, self.level+self.height))  #基点
    wsize = self.wspan + self.depthr * 2.0              #柱角寸
    wleng = self.wspan/2.0 + self.tops                  #基点から先端
    wspace = self.wspan + self.tops                     #先端から後柱芯
    height = wspace * tn + self.tarukd/cs               #壁基点高さ
    #屋根基点
    pt_org = pt + Vector((0, wleng, height))               
    #屋根
    object = kzb_cmp_roof.make_roof(self, pt_org)        #屋根作成（Y軸棟）
    object.parent = group
    #棟桁位置（母屋開始） self.rstyle == 'R':  レトロ限定
    length = self.lspan + self.koffs * 2 - self.hafud * 2
    pos = pt + Vector(( 0, -self.wspan/2.0, 0))
    kzb_mod_base.create_gcube(group, pos, 2, length, self.nokiw, self.nokid)
    #母屋数
    n = int(round(self.wspan/self.pitch))           #分割数
    if n == 0:
        return group
    psize = self.wspan/n                            #実行ピッチ
    vstep = Vector((0, psize, psize*tn))
    vside = Vector((self.lspan/2.0, 0, 0))
    if self.ktype == 'H':   # 庇構造（壁側母屋有無）
        n -= 1
    for i in range(n):
        #母屋
        pos += vstep
        kzb_mod_base.create_gcube(group, pos, 2, length, self.moya, self.moya)
        #小柱
        d = pos[2] - self.height
        pos1 = pos + vside
        pos2 = pos - vside
        obj = kzb_mod_base.create_cube(2, self.nokid, self.nokid, d)
        obj.location += pos1
        obj.parent = group
        obj = kzb_mod_base.create_cube(2, self.nokid, self.nokid, d)
        obj.location += pos2
        obj.parent = group
    return group
