sourceatlas 0.2.1

Analyze source code repositories and generate project statistics
use std::collections::HashMap;

use crate::{file_stats::FileStats, language::Language};

#[derive(Default)]
pub struct Report {
    files: Vec<FileAnalysis>,
    is_git_repo: bool,
    total_directories_scanned: usize,
    total_files_scanned: usize,
    total_files_analyzed: usize,
    total_files_skipped: usize,
    total_lines: usize,
}

impl Report {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn add_file(&mut self, file: FileAnalysis) {
        self.total_files_analyzed += 1;
        self.total_lines += file.stats.total_lines;
        self.files.push(file);
    }

    pub fn record_git_repo(&mut self) {
        self.is_git_repo = true;
    }

    pub fn record_directory_found(&mut self) {
        self.total_directories_scanned += 1;
    }

    pub fn record_file_found(&mut self) {
        self.total_files_scanned += 1;
    }

    pub fn record_skipped_file(&mut self) {
        self.total_files_skipped += 1
    }

    pub fn language_totals(&self) -> HashMap<Language, LanguageTotals> {
        let mut totals = HashMap::new();
        for file_report in &self.files {
            let entry = totals
                .entry(file_report.language)
                .or_insert(LanguageTotals::default());
            entry.lines += file_report.stats.total_lines;
        }
        totals
    }

    #[cfg(test)]
    pub fn total_files_found(&self) -> usize {
        self.total_files_scanned
    }

    #[cfg(test)]
    pub fn total_files_skipped(&self) -> usize {
        self.total_files_skipped
    }

    #[cfg(test)]
    pub fn total_files_analyzed(&self) -> usize {
        self.total_files_analyzed
    }

    #[cfg(test)]
    pub fn total_directories_found(&self) -> usize {
        self.total_directories_scanned
    }

    pub fn print_full_report(&self) {
        println!("-------------");
        println!("|SourceAtlas|");
        println!("-------------");
        println!("");
        if self.is_git_repo {
            println!("Scanning Git repo")
        }
        println!("");

        println!("LANGUAGE STATS");
        let language_totals = self.language_totals();
        for (language, totals) in language_totals {
            let percentage = (totals.lines as f64 / self.total_lines as f64) * 100.0;
            println!("{}: {:.1}%", language, percentage);
        }
        println!("");

        println!("DIRECTORIES");
        println!("--------");
        println!("total directories: {}", self.total_directories_scanned);
        println!("");

        // TODO: Decided if I can remove these in the future
        println!("TOTALS");
        println!("--------");
        println!("total files found: {}", self.total_files_scanned);
        println!("total files analyzed: {}", self.total_files_analyzed);
        println!("total files skipped: {}", self.total_files_skipped);
        println!("total lines: {}", self.total_lines);
    }
}

pub struct FileAnalysis {
    language: Language,
    stats: FileStats,
}

impl FileAnalysis {
    pub fn new(language: Language, stats: FileStats) -> Self {
        Self { language, stats }
    }
}

#[derive(Default)]
pub struct LanguageTotals {
    pub lines: usize,
}