public string Write(string outputDir, File file, TypeDefinition[] types)
        {
            var filename = GetFileName(file.Name) + ".html";
            using (var sw = new StreamWriter(Path.Combine(outputDir, filename)))
            {
                WriteHeader(sw, file, types);
                WriteSource(sw, file, types);
                WriteFooter(sw);
            }

            return filename;
        }
        private static void CreateFileModel(
            File file,
            string[] sourceLines,
            out List<LineAnnotation> beginAnnotations,
            out List<LineAnnotation> endAnnotations,
            out Line[] lines)
        {
            beginAnnotations = new List<LineAnnotation>();
            endAnnotations = new List<LineAnnotation>();
            lines = sourceLines.Select((x, i) => new Line() {Source = x, Number = i + 1}).ToArray();

            foreach (var annotation in file.Annotations)
            {
                var lineAnnotation = new LineAnnotation()
                {
                    Category = annotation.Category,
                    Message = annotation.Message,
                    References = annotation.References,
                    Type = annotation.Type,
                };
                if (annotation.Line <= 0)
                {
                    beginAnnotations.Add(lineAnnotation);
                }
                else if (annotation.Line > lines.Length)
                {
                    endAnnotations.Add(lineAnnotation);
                }
                else
                {
                    var size = annotation.Size > 0 ? annotation.Size : 1;
                    for (var i = annotation.Line; i < annotation.Line + size; i++)
                    {
                        var line = lines[i-1];
                        line.Count++;
                        line.Markers.Add(annotation.Type);
                    }
                    lines[Math.Min(annotation.Line + size - 2, lines.Length-1)].LineAnnotations.Add(lineAnnotation);
                }
            }
        }
        private void WriteSource(StreamWriter sw, File file, TypeDefinition[] types)
        {
            var sourceLines = new string[0];
            try
            {
                sourceLines = System.IO.File.ReadAllLines(file.Name);
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("File read error {0}: {1}", file.Name, ex.Message);
                sw.WriteLine("<div><div class='code'>File read error {0}</div></div>", WebUtility.HtmlEncode(ex.Message));
            }

            List<LineAnnotation> endAnnotations;
            List<LineAnnotation> beginAnnotations;
            Line[] lines;
            CreateFileModel(file, sourceLines, out beginAnnotations, out endAnnotations, out lines);

            sw.WriteLine("<table class='lineAnalysis'>");
            sw.WriteLine("<thead><tr><th></th><th>#</th><th>Line</th><th>Source</th></tr></thead>");
            sw.WriteLine("<tbody>");

            foreach (var annotation in beginAnnotations)
            {
                WriteAnnotationDiv(sw, annotation);
            }

            foreach (var line in lines)
            {
                WriteSourceLine(sw, line);
            }

            foreach (var annotation in endAnnotations)
            {
                WriteAnnotationDiv(sw, annotation);
            }

            sw.WriteLine("</tbody>");
            sw.WriteLine("</table>");
        }
        private void WriteHeader(StreamWriter sw, File file, TypeDefinition[] types)
        {
            var encodedfilename = WebUtility.HtmlEncode(file.Name);
            var total = file.Annotations.Length;

            sw.WriteLine("<html>");
            sw.WriteLine("<head>");
            sw.WriteLine("<meta charset='utf-8' />");
            sw.WriteLine("<title>{0} Report</title>", encodedfilename);
            sw.WriteLine("<link rel='stylesheet' type='text/css' href='report.css' />");
            sw.WriteLine("</head><body><div class='container'>");
            sw.WriteLine("<h1>Summary</h1>");
            sw.WriteLine("<table class='overview'>");
            sw.WriteLine("<colgroup>");
            sw.WriteLine("<col width='160' />");
            sw.WriteLine("<col />");
            sw.WriteLine("</colgroup>");
            sw.WriteLine("<tbody>");
            sw.WriteLine("<tr><th>File:</th><td>" + encodedfilename + "</td></tr>");

            var stats = file.Annotations.Select(x => x.Type)
                .GroupBy(x => x)
                .Select(x => new {Type = types.First(y => y.Name == x.Key).Display, Count = x.Count()})
                .OrderBy(x => x.Type)
                .ToArray();
            foreach (var stat in stats)
            {
                sw.WriteLine("<tr><th>{0}:</th><td>{1}</td></tr>", WebUtility.HtmlEncode(stat.Type), stat.Count);
            }
            if (stats.Length != 1)
            {
                sw.WriteLine("<tr><th>Total:</th><td>" + total + "</td></tr>");
            }
            sw.WriteLine("</tbody>");
            sw.WriteLine("</table>");
            sw.WriteLine("<h1>Sourcode</h1>");
        }