import networkx as nx
import matplotlib.pyplot as plt
import csv

# タスクとそのdurationをCSVファイルから読み込む
tasks = {}
with open('float.csv', newline='', encoding='utf-8') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        tasks[row['CODE']] = int(row['DAYS'])

# タスク間の依存関係をCSVファイルから読み込む
dependencies = []
with open('float.csv', newline='', encoding='utf-8') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        dependencies.append((row['CODE'], row['PREDECESSORS']))

# グラフを作成
G = nx.DiGraph()

# タスクをノードとして追加し、durationを属性として設定
for CODE, DAYS in tasks.items():
    G.add_node(CODE, duration=DAYS)

# タスク間の依存関係をエッジとして追加
G.add_edges_from(dependencies)



cycles = list(nx.simple_cycles(G))

# 検出されたサイクルの表示
print("検出されたサイクル:", cycles)

# トポロジカルソートして最早開始時刻（ES）を計算
es = {node: 0 for node in G.nodes()}
for node in nx.topological_sort(G):
    es[node] = max([es[p] + G.nodes[p]["duration"] for p in G.predecessors(node)], default=0)

# 逆向きのグラフを用いて最遅開始時刻（LS）を計算
ls = {node: es[node] for node in G.nodes()}
for node in list(reversed(list(nx.topological_sort(G)))):
    ls[node] = min([ls[s] - G.nodes[node]["duration"] for s in G.successors(node)], default=max(ls.values()))



# クリティカルパスを計算
float_time = {node: ls[node] - es[node] for node in G.nodes()}
critical_path = [node for node, float_time in float_time.items() if float_time == 0]



# 各経路にフロートタイムを追加
paths_with_float_time = []
for start_node in G.nodes():
    for end_node in G.nodes():
        if start_node != end_node:
            paths = list(nx.all_simple_paths(G, source=start_node, target=end_node))
            for path in paths:
                path_duration = sum([G.nodes[node]["duration"] for node in path[:-1]])
                float_time = ls[end_node] - es[start_node] - path_duration
                # 経路の各ノードをA列からC列に分割して格納
                path_str = ",".join(path)
                path_parts = path_str.split(",")
                writer_row = {'start':path_parts[-1], 'route': ",".join(path_parts[1:-1]), 'end': path_parts[0], 'Float Time': float_time}
                paths_with_float_time.append(writer_row)

# CSVファイルに経路とフロートタイムを格納（A列からC列に分割）
with open('loads_float.csv', mode='w', newline='') as csvfile:
    fieldnames = ['end', 'route', 'start', 'Float Time']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    writer.writerows(paths_with_float_time)

print("CSVファイルに経路とフロートタイムが保存されました。")
print("クリティカルパス:", critical_path)

float_times_per_task = {node: ls[node] - es[node] for node in G.nodes()}

# タスクごとのフロートタイムをCSVに追加

with open('tasks_float.csv', mode='a', newline='') as csvfile:
    fieldnames = ['Task', 'Float Time', 'Critical_Pass']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    # ヘッダーがまだ存在しない場合はヘッダーを書き込む
    if csvfile.tell() == 0:
        writer.writeheader()

    # タスクごとにフロートタイムを書き込む
    for task, float_time in float_times_per_task.items():
        # フロートタイムが0なら'Yes'、それ以外なら'No'を判定
        Critical_Pass = 'Yes' if float_time == 0 else 'No'
        writer.writerow({'Task': task, 'Float Time': float_time, 'Critical_Pass': Critical_Pass})

print("タスクごとのフロートタイム:")
for task, float_time in float_times_per_task.items():
    print(f"{task}: {float_time}")
print("CSVファイルにタスクごとのフロートタイムが保存されました。")



# レイアウト調整
pos = nx.spring_layout(G, seed=42, k=15)  # グラフのレイアウトを微調整

# グラフを描画
nx.draw(G, pos, with_labels=False, node_size=500, node_color="lightblue", font_size=10, font_weight="bold", node_shape="o")
nx.draw_networkx_labels(G, pos, labels={k: f"{k}\n{duration} times" for k, duration in tasks.items()}, font_size=10, font_weight="bold")
plt.show()
