class FileAnalyzer { constructor() { this.files = []; this.results = []; this.initializeEventListeners(); } initializeEventListeners() { const uploadBtn = document.getElementById('uploadBtn'); const fileInput = document.getElementById('fileInput'); const analyzeBtn = document.getElementById('analyzeBtn'); uploadBtn.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', (e) => this.handleFileSelection(e)); analyzeBtn.addEventListener('click', () => this.analyzeFiles()); } handleFileSelection(event) { const files = Array.from(event.target.files); if (files.length === 0) return; this.files = files; this.displayFileList(); document.getElementById('analyzeBtn').classList.remove('hidden'); } displayFileList() { const fileList = document.getElementById('fileList'); const fileItems = document.getElementById('fileItems'); fileItems.innerHTML = ''; this.files.forEach((file, index) => { const fileItem = document.createElement('div'); fileItem.className = 'file-item flex items-center justify-between bg-cyan-50 rounded-lg p-3 border border-cyan-200'; fileItem.innerHTML = `
${file.name}
${this.formatFileSize(file.size)} `; fileItems.appendChild(fileItem); }); fileList.classList.remove('hidden'); feather.replace(); } formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } async analyzeFiles() { if (this.files.length < 2) { this.showNotification('Please select at least 2 files to analyze', 'error'); return; } this.showLoading(true); try { const fileContents = await this.readAllFiles(); this.results = this.findLCSAcrossFiles(fileContents); this.displayResults(); } catch (error) { this.showNotification('Error analyzing files: ' + error.message, 'error'); } finally { this.showLoading(false); } } readAllFiles() { const promises = this.files.map(file => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = e => resolve({ name: file.name, content: e.target.result, size: file.size }); reader.onerror = () => reject(new Error(`Failed to read file: ${file.name}`)); reader.readAsText(file); }); }); return Promise.all(promises); } findLCSAcrossFiles(fileContents) { const results = []; const lcsMap = new Map(); let tagCounter = 0; // Generate all possible file pairs for (let i = 0; i < fileContents.length; i++) { for (let j = i + 1; j < fileContents.length; j++) { const file1 = fileContents[i]; const file2 = fileContents[j]; const lcs = this.findLCS(file1.content, file2.content); if (lcs.length > 10) { // Only consider significant LCS const key = this.normalizeLCS(lcs); if (!lcsMap.has(key)) { const tag = String.fromCharCode(65 + (tagCounter++ % 26)); // A, B, C, ... lcsMap.set(key, { tag: tag, content: lcs, length: lcs.length, files: new Set([file1.name, file2.name]) }); } else { const existing = lcsMap.get(key); existing.files.add(file1.name); existing.files.add(file2.name); } } } // Convert map to array and sort by length return Array.from(lcsMap.values()) .sort((a, b) => b.length - a.length) .slice(0, 10); // Limit to top 10 results } findLCS(str1, str2) { const m = str1.length; const n = str2.length; const dp = Array(m + 1).fill().map(() => Array(n + 1).fill(0)); let maxLength = 0; let endIndex = 0; for (let i = 1; i <= m; i++) { for (let j = 1; j <= n; j++) { if (str1[i - 1] === str2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; if (dp[i][j] > maxLength) { maxLength = dp[i][j]; endIndex = i - 1; } } else { dp[i][j] = 0; } } } return str1.substring(endIndex - maxLength + 1, endIndex + 1); } normalizeLCS(lcs) { // Remove whitespace and normalize for comparison return lcs.replace(/\s+/g, '').trim(); } displayResults() { const resultsSection = document.getElementById('resultsSection'); const resultsContainer = document.getElementById('resultsContainer'); resultsContainer.innerHTML = ''; if (this.results.length === 0) { resultsContainer.innerHTML = `

No significant common patterns found

`; } else { this.results.forEach((result, index) => { const resultCard = document.createElement('div'); resultCard.className = 'fade-in gradient-border rounded-xl p-6 bg-white'; resultCard.style.animationDelay = `${index * 0.1}s`; const fileList = Array.from(result.files).join(', '); const preview = result.content.length > 200 ? result.content.substring(0, 200) + '...' : result.content; resultCard.innerHTML = `
${result.tag}

Pattern ${result.tag}

${result.length} characters

${result.files.size} files

Files:

${fileList}

Common Content Preview:

${this.escapeHtml(preview)}
`; resultsContainer.appendChild(resultCard); }); } resultsSection.classList.remove('hidden'); feather.replace(); // Scroll to results resultsSection.scrollIntoView({ behavior: 'smooth' }); } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } showLoading(show) { const loadingState = document.getElementById('loadingState'); if (show) { loadingState.classList.remove('hidden'); } else { loadingState.classList.add('hidden'); } } showNotification(message, type = 'info') { // Create notification element const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 p-4 rounded-xl shadow-lg z-50 fade-in ${ type === 'error' ? 'bg-red-500 text-white' : 'bg-cyan-500 text-white' }`; notification.innerHTML = `
${message}
`; document.body.appendChild(notification); feather.replace(); // Remove after 5 seconds setTimeout(() => { notification.remove(); }, 5000); } } // Initialize the application when DOM is loaded document.addEventListener('DOMContentLoaded', () => { new FileAnalyzer(); });