'use strict';

const fs = require('fs-extra');
const path = require('path');
const merge = require('merge');

const auto = require('run-auto');
const section = require('./section').section;
const Language = require('./language').Language;

class File {
  constructor(project, filename, contents) {
    this.project = project;
    
    this.filename = filename;
    this.path = filename;
    
    this.contents = contents;

    this.index = false;
    this.sections = [];
    this.html = '';

    this.default_template_data = merge(this.project.default_template_data, {});
  }
  preprocess_file(data, callback) {
    callback(null, data);
  }
  split_lines(data, callback) {
    var lines = data.split(/\r?\n/);

    callback(null, lines);
  }
  detect_language(data, callback) {
    this.language = new Language(this.project, this);
    callback(null, this.language);
  }
  parse_lines(data, lang, callback) {
    var sections = [];

    var scope = this;
    
    function add_section() {
      if(sections.length == 0 || !current_section().is_empty()) {
        sections.push(section.create(scope.project, scope, lang));
      }
      
    }
    add_section();
    function current_section() {
      return sections[sections.length-1];
    }
    var in_comment = false,
        in_multi = false,
        line,
        comment,
        i;
    for(i=0; i<data.length; i++) {
      line = data[i];
      if(lang.is_comment(line) || in_multi) {

        if(lang.starts_multi_comment(line) && !lang.ends_multi_comment(line))
          in_multi = true;
        else if(lang.ends_multi_comment(line))
          in_multi = false;
        comment = lang.strip_comment(line);
        if(!in_comment)
          add_section();
        current_section().comment += comment + '\n';
        in_comment = true;
        
      } else {
        
        in_comment = false;
        in_multi = false;
        if(sections.length == 1 && !current_section().code.trim() && !line.trim()) continue;
        if(!current_section().code.trim() && !line.trim()) continue;
        current_section().code += line + '\n';
      }
      
    };
    for(i=0; i<sections.length; i++) {
      sections[i].done();
    }

    this.sections = sections;
    callback(null, sections);
    
  }

  get_rel_path() {
    return './' + path.relative('/' + this.get_link(), '/');
  }

  get_rel_link(link) {
    return path.relative(this.get_rel_path(), link);
  }
  render(sections, language, callback) {
    
    if(!language) language = this.language;

    for(i=0; i<this.sections.length; i++) {
      this.sections[i].done();
    }

    var i;
    this.default_template_data.path = this.get_rel_path();
    var filenames = this.project.get_link_filenames(this);

    var md = null;

    if(this.sections.length == 1 && this.sections[0].code_is_markdown) {
      md = this.sections[0].code_highlighted;
    }

    var classes = [];

    if(this.index) classes.push('index');
    
    if(md) classes.push('markdown');
    else   classes.push('code');

    var html_sections = '';

    for(i=0; i<this.sections.length; i++) {
      html_sections += this.sections[i].render();
    }

    var html_filenames = '';

    for(i=0; i<filenames.length; i++) {
      html_filenames += this.project.templates.file.render(merge(this.default_template_data, filenames[i]));
    }

    var html_links = '';

    var links = Object.keys(this.project.options.links).sort();

    var type_names = {
      github: {
        name: "GitHub",
        desc: "View on GitHub"
      },
      twitter: {
        name: "Twitter",
        desc: "Follow on Twitter"
      },
      home: {
        name: "Homepage",
        desc: "Project homepage"
      }
    };

    for(i=0; i<links.length; i++) {
      var type = links[i]
      var link = this.project.options.links[type];

      if(!(type in type_names)) {
        this.project.fire('link-type-unknown', type);
        continue;
      }
      
      html_links += this.project.templates.link.render({
        url: link,
        name: type_names[type].name,
        desc: type_names[type].desc,
        type: type
      });
    }
    this.html = this.project.templates.page.render(merge(this.default_template_data, {
      title: (this.index ? this.project.options.name : this.filename),
      version: this.project.options.version,
      language: this.language.name.human,
      markdown: md,
      index: this.index,
      filename: this.filename,
      files: html_filenames,
      classes: classes.join(' '),
      sections: html_sections,
      links: html_links
    }));

    callback(null, this.html);
  }
  get_output_filename() {
    return path.join(this.project.options.output, this.path, 'index.html');
  }
  get_link() {
    if(this.index) return './';
    return path.join(this.path, '/');
  }
  write(callback) {

    var filename = this.get_output_filename();

    var scope = this;

    fs.mkdirs(path.dirname(filename), function (err) {
      if(err) {
        callback(err, null);
        return;
      }
      fs.writeFile(filename, scope.html, function(err) {
        
        if(err) {
          callback(err, null);
          return;
        }

        callback(null, null);

      });      
      
    });


  }
  parse_file(err, data, callback) {

    var scope = this;
    if(err) {
      callback(err, this);
      return;
    }
    auto({
      
      preprocess: function(next) {
        scope.preprocess_file.call(scope, data, function(err, data) {

          next(err, data);
          
        });
      },
      
      split_lines: ['preprocess', function(next, results) {
        
        scope.split_lines.call(scope, results.preprocess, function(err, data) {
          
          next(err, data);
          
        });
          
      }],
      
      language: ['preprocess', function(next, results) {
        
        scope.detect_language.call(scope, results.preprocess, function(err, data) {
          
          next(err, data);
          
        });
          
      }],
      
      parse_lines: ['split_lines', 'language', function(next, results) {

        scope.parse_lines.call(scope, results.split_lines, results.language, function(err, data) {
          
          next(err, data);
          
        });
          
      }],
      
      render: ['parse_lines', 'language', function(next, results) {
        
        scope.render.call(scope, results.parse_lines, results.language, function(err, data) {

          scope.html = data;
          
          next(err, data);
          
        });
          
      }],
      
      write: ['render', function(next, results) {
        
        scope.write.call(scope, function(err, data) {

          next(err, data);
          
        });
          
      }]
      
    }, function(err, results) {
      callback(err, scope);
    });
    
  }

  parse(callback) {
    var scope = this;

    if(this.contents) {
      this.parse_file(null, this.contents, callback);
    } else {
      fs.readFile(this.filename, 'utf8', function(err, data) {
        scope.parse_file.call(scope, err, data, callback);
      });
    }

  }
  run(callback) {
    this.parse(callback);
  }
  
}

exports.File = File;