'''
把观察者挂到自己的处理队列上
'''

import os
import re
import threading
from queue import Queue
from collections import Counter
from abc import ABC, abstractmethod

# 观察者接口
class Observer(ABC):
    @abstractmethod
    def update(self, word_counts: Counter):
        pass

# 具体观察者：打印前 10 高频词
class PrintTopWordsObserver(Observer):
    def update(self, word_counts: Counter):
        print("Top 10 高频词:")
        for word, count in word_counts.most_common(10):
            print(f"{word}: {count}")

# 具体观察者：保存词频到文件
class SaveToFileObserver(Observer):
    def __init__(self, output_file):
        self.output_file = output_file

    def update(self, word_counts: Counter):
        try:
            with open(self.output_file, 'w', encoding='utf-8') as f:
                for word, count in word_counts.most_common(10):
                    f.write(f"{word}: {count}\n")
            print(f"词频已保存到 {self.output_file}")
        except Exception as e:
            print(f"保存失败: {e}")

# 词频统计器（主题）
class WordFrequencyCounter:
    def __init__(self):
        self.observers = []
        self.counter = Counter()
        self.queue = Queue()
        self.lock = threading.Lock()

    def add_observer(self, observer: Observer):
        self.observers.append(observer)

    def remove_observer(self, observer: Observer):
        self.observers.remove(observer)

    def notify_observers(self):
        for observer in self.observers:
            observer.update(self.counter)

    def process_file(self):
        while True:
            try:
                file_path = self.queue.get_nowait()
            except:
                break
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    text = f.read().lower()
                    words = re.findall(r'\b\w+\b', text)
                    with self.lock:
                        self.counter.update(words)
            except Exception as e:
                print(f"Error processing {file_path}: {e}")
            finally:
                self.queue.task_done()

    def count_words(self, files, num_threads=4):
        # 将文件路径放入队列
        for file_path in files:
            self.queue.put(file_path)
        
        # 创建并启动线程
        threads = [threading.Thread(target=self.process_file) for _ in range(num_threads)]
        for t in threads:
            t.start()
        for t in threads:
            t.join()

        # 通知所有观察者
        self.notify_observers()

def main():
    # 获取文件列表
    data_dir = 'data'
    files = [os.path.join(data_dir, f) for f in os.listdir(data_dir) if f.endswith('.txt')]
    
    # 创建词频统计器
    counter = WordFrequencyCounter()
    
    # 添加观察者
    counter.add_observer(PrintTopWordsObserver())
    counter.add_observer(SaveToFileObserver("word_frequency.txt"))
    
    # 统计词频并通知观察者
    counter.count_words(files)

if __name__ == '__main__':
    main()