package main

import (
  "os"
  "fmt"
  "strings"
  "strconv"
)

type LineRange struct {
  Start int
  End int
}

func srcMapDeserialize(s string) map[string]LineRange {
  self := map[string]LineRange{}
  totalLines := 0
  lines := strings.Split(s, "\n");
  for _, l := range lines {
    file := ""
    nLines := 0
    
    fmt.Sscanf(l, "%s\t%d", &file, &nLines)
    rg := LineRange{
      Start: totalLines,
      End: totalLines + nLines,
    }
    totalLines += nLines
    self[file] = rg;
  }
  return self
}

func buildOutputTransform(buildOutput string, srcMap map[string]LineRange) string {
  self := ""
  lines := strings.Split(buildOutput, "\n")
  for _, l := range lines {
    parts := strings.Split(l, ":")
    if (len(parts) > 1) {
      lineNumber, err := strconv.ParseInt(parts[1], 10, 32)
      if err == nil {
        for f, rg := range srcMap {
          if lineNumber <= int64(rg.End) && lineNumber > int64(rg.Start) {
            self += strings.Replace(
              strings.Replace(l, parts[1], strconv.FormatInt(lineNumber - int64(rg.Start), 10), 1),
              parts[0], f, 1) + "\n";
          }
        }      
      } else {
        panic(err.Error())
      }
    } else {
      self += l
    }
  }
  return self
}

func main() {
  if len(os.Args) == 3 {
    errFilename := os.Args[1];
    srcMapFilename := os.Args[2];
    errFile, err1 := os.ReadFile(errFilename);
    srcMapFile, err2 := os.ReadFile(srcMapFilename);
    if err1 != nil || err2 != nil {
      panic("Couldn't open either the error temp file or the source map");
    }
    srcMap := srcMapDeserialize(string(srcMapFile[:]))
    fmt.Print(buildOutputTransform(string(errFile[:]), srcMap))
  } else {
    fmt.Println("usage: sourcemapper ERRFILE SRCMAP");
  }
}