Source: frontend/js/controllers/VSOMController.js

import log from 'loglevel';
import { VSOMVisualization } from '../components/vsom/VSOMVisualization.js';
import { vsomService } from '../services/VSOMService.js';

/**
 * Controller for the VSOM tab
 */
class VSOMController {
  constructor() {
    this.logger = log.getLogger('vsom:controller');
    this.vsom = null;
    this.currentTab = 'som-grid';
    this.initialized = false;
    
    // Bind methods
    this.init = this.init.bind(this);
    this.setupEventListeners = this.setupEventListeners.bind(this);
    this.handleTabChange = this.handleTabChange.bind(this);
    this.loadSOMGrid = this.loadSOMGrid.bind(this);
    this.startTraining = this.startTraining.bind(this);
    this.stopTraining = this.stopTraining.bind(this);
    this.loadFeatureMaps = this.loadFeatureMaps.bind(this);
    this.loadClusters = this.loadClusters.bind(this);
    this.loadData = this.loadData.bind(this);
  }

  /**
   * Initialize the VSOM controller
   */
  async init() {
    if (this.initialized) {
      this.logger.debug('VSOMController already initialized');
      return;
    }
    
    this.logger.debug('Initializing VSOMController');
    
    // Initialize the VSOM visualization
    const container = document.getElementById('vsom-container');
    if (!container) {
      this.logger.error('VSOM container element not found');
      return;
    }
    
    try {
      this.vsom = new VSOMVisualization(container, {
        logLevel: 'debug',
        onError: (error) => {
          this.logger.error('VSOM error:', error);
          this.showError(error.message || 'An error occurred');
        }
      });
      
      await this.vsom.init();
      this.setupEventListeners();
      this.initialized = true;
      this.logger.info('VSOMController initialized');
      
      // Load initial tab
      this.handleTabChange({ target: document.querySelector('[data-inner-tab="som-grid"]') });
      
    } catch (error) {
      this.logger.error('Failed to initialize VSOMController:', error);
      this.showError('Failed to initialize VSOM visualization');
    }
  }

  /**
   * Set up event listeners for the VSOM tab
   */
  setupEventListeners() {
    // Tab navigation
    document.querySelectorAll('.vsom-tabs .tab-inner-btn').forEach(btn => {
      btn.addEventListener('click', this.handleTabChange);
    });
    
    // Training controls
    const startBtn = document.getElementById('start-som-training');
    const stopBtn = document.getElementById('stop-som-training');
    
    if (startBtn) startBtn.addEventListener('click', this.startTraining);
    if (stopBtn) stopBtn.addEventListener('click', this.stopTraining);
    
    // Load buttons
    const loadDataBtn = document.getElementById('load-som-data');
    const loadGridBtn = document.getElementById('load-som-grid');
    const loadFeaturesBtn = document.getElementById('load-som-features');
    const loadClustersBtn = document.getElementById('load-som-clusters');
    
    if (loadDataBtn) loadDataBtn.addEventListener('click', this.loadData);
    if (loadGridBtn) loadGridBtn.addEventListener('click', this.loadSOMGrid);
    if (loadFeaturesBtn) loadFeaturesBtn.addEventListener('click', this.loadFeatureMaps);
    if (loadClustersBtn) loadClustersBtn.addEventListener('click', this.loadClusters);
    
    // Window resize
    window.addEventListener('resize', () => {
      if (this.vsom) {
        this.vsom.handleResize();
      }
    });
  }

  /**
   * Handle tab changes
   * @param {Event} event - The click event
   */
  handleTabChange(event) {
    const tabId = event.target.getAttribute('data-inner-tab');
    if (!tabId) return;
    
    this.logger.debug(`Switching to tab: ${tabId}`);
    
    // Update active tab UI
    document.querySelectorAll('.vsom-tabs .tab-inner-btn').forEach(btn => {
      btn.classList.remove('active');
    });
    event.target.classList.add('active');
    
    // Hide all tab content
    document.querySelectorAll('.vsom-tabs .inner-tab-content').forEach(content => {
      content.classList.remove('active');
    });
    
    // Show selected tab content
    const content = document.getElementById(tabId);
    if (content) {
      content.classList.add('active');
    }
    
    // Load data for the selected tab
    this.currentTab = tabId;
    switch (tabId) {
      case 'som-grid':
        this.loadSOMGrid();
        break;
      case 'som-features':
        this.loadFeatureMaps();
        break;
      case 'som-clusters':
        this.loadClusters();
        break;
    }
  }

  /**
   * Load and display the SOM grid
   */
  async loadSOMGrid() {
    if (!this.vsom) return;
    
    try {
      this.showLoading('Loading SOM grid...');
      
      // Get SOM state from the server
      const state = await vsomService.getGridState();
      
      // Transform data for visualization
      const nodes = state.nodes.map(node => ({
        id: node.id,
        x: node.x,
        y: node.y,
        activation: node.activation,
        weight: node.weight,
        metadata: node.metadata || {}
      }));
      
      // Update the visualization
      await this.vsom.setVisualizationType('grid');
      await this.vsom.update({ nodes });
      
      this.hideLoading();
    } catch (error) {
      this.logger.error('Failed to load SOM grid:', error);
      this.showError('Failed to load SOM grid: ' + (error.message || 'Unknown error'));
    }
  }

  /**
   * Start SOM training
   */
  async startTraining() {
    if (!this.vsom) return;
    
    try {
      this.showLoading('Starting training...');
      
      // Get training data (this would come from your application state)
      const trainingData = []; // TODO: Get actual training data
      
      if (!trainingData || trainingData.length === 0) {
        throw new Error('No training data available');
      }
      
      // Start training
      await vsomService.train(trainingData, {
        epochs: 100,
        batchSize: 32,
        learningRateDecay: 0.99,
        radiusDecay: 0.99
      });
      
      // Enable/disable controls
      document.getElementById('start-som-training').disabled = true;
      document.getElementById('stop-som-training').disabled = false;
      
      this.hideLoading();
    } catch (error) {
      this.logger.error('Failed to start training:', error);
      this.showError('Failed to start training: ' + (error.message || 'Unknown error'));
    }
  }

  /**
   * Stop SOM training
   */
  async stopTraining() {
    try {
      this.showLoading('Stopping training...');
      
      await vsomService.stopTraining();
      
      // Enable/disable controls
      document.getElementById('start-som-training').disabled = false;
      document.getElementById('stop-som-training').disabled = true;
      
      this.hideLoading();
    } catch (error) {
      this.logger.error('Failed to stop training:', error);
      this.showError('Failed to stop training: ' + (error.message || 'Unknown error'));
    }
  }

  /**
   * Load and display feature maps
   */
  async loadFeatureMaps() {
    if (!this.vsom) return;
    
    try {
      this.showLoading('Loading feature maps...');
      
      // Get feature maps from the server
      const featureMaps = await vsomService.getFeatureMaps();
      
      // Update the visualization
      await this.vsom.setVisualizationType('featureMaps');
      await this.vsom.update({ featureMaps });
      
      this.hideLoading();
    } catch (error) {
      this.logger.error('Failed to load feature maps:', error);
      this.showError('Failed to load feature maps: ' + (error.message || 'Unknown error'));
    }
  }

  /**
   * Load and display clusters
   */
  async loadClusters() {
    if (!this.vsom) return;
    
    try {
      this.showLoading('Loading clusters...');
      
      // Get clusters from the server
      const clusters = await vsomService.cluster({
        method: 'kmeans',
        params: { k: 5 }
      });
      
      // Update the visualization
      await this.vsom.setVisualizationType('clustering');
      await this.vsom.update({ clusters });
      
      this.hideLoading();
    } catch (error) {
      this.logger.error('Failed to load clusters:', error);
      this.showError('Failed to load clusters: ' + (error.message || 'Unknown error'));
    }
  }

  /**
   * Show loading indicator
   * @param {string} message - Loading message
   */
  showLoading(message = 'Loading...') {
    const loadingEl = document.getElementById('vsom-loading');
    if (loadingEl) {
      loadingEl.textContent = message;
      loadingEl.style.display = 'block';
    }
  }

  /**
   * Hide loading indicator
   */
  hideLoading() {
    const loadingEl = document.getElementById('vsom-loading');
    if (loadingEl) {
      loadingEl.style.display = 'none';
    }
  }

  /**
   * Load data into VSOM
   */
  async loadData() {
    try {
      this.showLoading('Loading data into VSOM...');
      
      // Create a simple data input dialog
      const dataInput = prompt(
        'Enter data in JSON format:\n\n' +
        'Example formats:\n' +
        '1. Entities: {"type":"entities","entities":[{"uri":"http://example.org/e1","content":"text","type":"concept"}]}\n' +
        '2. SPARQL: {"type":"sparql","endpoint":"http://localhost:3030/dataset/query","query":"SELECT * WHERE {?s ?p ?o} LIMIT 10"}\n' +
        '3. Sample data: {"type":"sample","count":50}'
      );
      
      if (!dataInput) {
        this.hideLoading();
        return;
      }
      
      let data;
      try {
        data = JSON.parse(dataInput);
      } catch (parseError) {
        throw new Error('Invalid JSON format: ' + parseError.message);
      }
      
      // Handle sample data generation
      if (data.type === 'sample') {
        const count = data.count || 50;
        const sampleData = await vsomService.generateSampleData(count);
        data = {
          type: 'entities',
          entities: sampleData
        };
      }
      
      // Load data into VSOM
      const result = await vsomService.loadData(data);
      
      this.hideLoading();
      
      // Show success message
      const successMsg = `Data loaded successfully! ${result.message || ''}`;
      alert(successMsg);
      
      // Refresh the current view
      if (this.currentTab === 'som-grid') {
        this.loadSOMGrid();
      }
      
    } catch (error) {
      this.logger.error('Failed to load data:', error);
      this.showError('Failed to load data: ' + (error.message || 'Unknown error'));
    }
  }

  /**
   * Show error message
   * @param {string} message - Error message
   */
  showError(message) {
    const errorEl = document.getElementById('vsom-error');
    if (errorEl) {
      errorEl.textContent = message;
      errorEl.style.display = 'block';
      
      // Hide after 5 seconds
      setTimeout(() => {
        errorEl.style.display = 'none';
      }, 5000);
    }
    
    this.hideLoading();
  }
}

// Export class and singleton instance
export { VSOMController };
export const vsomController = new VSOMController();

// Auto-initialize when DOM is loaded
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', () => vsomController.init());
} else {
  vsomController.init();
}