var path = require('path');
var merge = require('merge');
var c = require('./class').class;
var languages_list = require('./languages');
var colors = require('./github-colors');

exports.normalize_language = function(l, name) {
  l.color = colors[(l.name.color || l.name.hljs || l.name.abbr || name).toLowerCase()] || 'transparent';
  if(!('abbr' in l.name)) l.name.abbr = l.extensions[0];
  return l;
};

exports.get_language = function(extension, extra_languages) {
  
  var languages = languages_list, i;
  if(extra_languages) {
    for(i in extra_languages) {
      languages[i] = merge(languages[i], extra_languages[i]);
    }
  }
  
  for(i in languages) {
    if(!('extensions' in languages[i])) continue;

    if(languages[i].extensions.indexOf(extension) >= 0) {
      return [exports.normalize_language(languages[i], i), i];
    }
  }
  
  return [
    {
      name: { hljs: 'auto', human: 'Autodetected (Unknown)', abbr: 'AUTO' },
      color: '#000',
      extensions: []
    },
    'auto'
  ];
};

class Language {
  
  constructor(project, file) {
    this.name = {};
    
    this.single = [];
    
    this.multi = [];
    this.ignore = [];

    var language = exports.get_language(path.extname(file.filename).substr(1), project.options.languages);
    var language_name = language[1];
    
    language = language[0];

    if(language_name != 'auto') {
      this.name = language.name;

      if(!('human' in this.name)) this.name.human = language_name;
      
      if('single' in language) this.single = language.single;
      if('multi' in language)  this.multi = language.multi;
      if('ignore' in language) this.ignore = language.ignore;
    } else {
      project.emit('language-not-found', { filename: file.filename });
      this.name = {
        hljs: 'auto',
        human: 'Autodetected (Unknown)',
        abbr: 'AUTO'
      };
      this.single = [
        '//',
        ';',
        '--',
        '#'
      ];

      this.multi = [
        ['/*', '*', '*/']
      ];

    }
    
  }

  should_ignore_comment(comment) {
    comment = comment.trim();

    for(var i=this.ignore.length-1; i>=0; i--) {
      if(comment.startsWith(this.ignore[i])) {
        return true;
      }
    }

    return false;
    
  }

  is_single_comment(line) {
    line = line.trim() + ' ';

    for(var i=this.single.length-1; i>=0; i--) {
      if(line.startsWith(this.single[i] + ' ')) {
        return !this.should_ignore_comment(this.strip_single_comment(line));
      }
    }
    
    return false;
  }

  starts_multi_comment(line) {
    
    line = line.trim();

    for(var i=this.multi.length-1; i>=0; i--) {
      if(line.startsWith(this.multi[i][0]) || line == this.multi[i][0]) return true;
    }

    return false;
  }

  ends_multi_comment(line) {
    
    line = line.trim();
    
    for(var i=this.multi.length-1; i>=0; i--) {
      if(line.endsWith(this.multi[i][2])) return true;
    }
    
    return false;
  }

  strip_single_comment(line) {
    line = line.trim();
    var c;
    
    for(var i=this.single.length-1; i>=0; i--) {
      c = this.single[i];
      
      if(line.startsWith(c)) {
        return line.substr(c.length).trimRight().substr(1);
      }
      
    }
    
    return line;
  }

  strip_multi_comment_end(line, end) {
    line = line.trim();

    if(line.endsWith(end)) {
      return line.substr(0, line.length - end.length).trimRight();
    }
    
    return line;
  }
  
  strip_multi_comment(line) {
    
    line = line.trim();
    var s, m, e;
    for(var i=this.multi.length-1; i>=0; i--) {
      s = this.multi[i][0];
      m = this.multi[i][1];
      e = this.multi[i][2];
      if(line.startsWith(s)) {
        line = line.substr(s.length);

        if(line.startsWith(m)) {
          line = line.substr(m.length).trimRight();

          if(/\s/.test(line[0]) && !/\s/.test(line[1])) {
            line = line.substr(1);
          }
          
        }

        return this.strip_multi_comment_end(line, e);
      } else if(line.endsWith(e)) {
        return this.strip_multi_comment_end(line, e);
      } else if(m && line.startsWith(m)) {

        return this.strip_multi_comment_end(line.substr(m.length), e);
      } else {
        continue;
      }
      
    }
    
    return line;
  }

  is_comment(line) {
    return this.is_single_comment(line) || this.starts_multi_comment(line);
  }

  strip_comment(line) {
    if(this.is_single_comment(line))
      return this.strip_single_comment(line);
    else
      return this.strip_multi_comment(line);
    return line;
  }

}

exports.Language = Language;