package com.ibm.wala.cast.js.html;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;

import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
import com.ibm.wala.cast.tree.impl.AbstractSourcePosition;

public class RangeFileMapping implements FileMapping {

  public static class Range {
    private final int rangeStart;
    private final int rangeEnd;
    private final int rangeStartingLine;
    private final int rangeEndingLine;

    public boolean includes(Position offset) {
      return 
        offset.getFirstOffset() != -1? 
        rangeStart <= offset.getFirstOffset() && offset.getLastOffset() <= rangeEnd:
        rangeStartingLine <= offset.getFirstLine() && 
          (offset.getLastLine() == -1? offset.getFirstLine(): offset.getLastLine()) <= rangeEndingLine;
    }

    public Range(int rangeStart, int rangeEnd, int rangeStartingLine, int rangeEndingLine) {
      super();
      this.rangeStart = rangeStart;
      this.rangeEnd = rangeEnd;
      this.rangeStartingLine = rangeStartingLine;
      this.rangeEndingLine = rangeEndingLine;
    }

    public int getStart() {
      return rangeStart;
    }

    public int getEnd() {
      return rangeEnd;
    }

    public int getStartingLine() {
      return rangeStartingLine;
    }

    public int getEndingLine() {
      return rangeEndingLine;
    }
     
    public String toString() {
      return "{"+rangeStart+"->"+rangeEnd+"}";
    }
  }

  private final Range range;
  private final URL includedURL;
  private final Position includePosition;
    
  public RangeFileMapping(int rangeStart, int rangeEnd, int rangeStartingLine, int rangeEndingLine, Position parentPosition, URL url) {
    assert parentPosition != null;
    this.range = new Range(rangeStart, rangeEnd, rangeStartingLine, rangeEndingLine);
    this.includePosition = parentPosition;
    includedURL = url;
  }

  public String toString() {
    return range + ":" + includePosition;
  }
  
  @Override
  public IncludedPosition getIncludedPosition(final Position offset) {
    if (range.includes(offset)) {
      class Pos extends AbstractSourcePosition implements IncludedPosition {
        @Override
        public int getFirstLine() {
          // line numbers are decreed to start at 1, rather than 0
          return offset.getFirstLine() - range.getStartingLine() + 1;
        }
        @Override
        public int getLastLine() {
          return offset.getLastLine() == -1? -1: offset.getLastLine()-range.getStartingLine()+1;
        }
        @Override
        public int getFirstCol() {
          return offset.getFirstCol();
        }
        @Override
        public int getLastCol() {
          return offset.getLastCol();
        }
        @Override
        public int getFirstOffset() {
          return offset.getFirstOffset() == -1? -1: offset.getFirstOffset()-range.getStart();
        }
        @Override
        public int getLastOffset() {
          return offset.getLastOffset() == -1? -1: offset.getLastOffset()-range.getStart();
        }
        @Override
        public URL getURL() {
          return includedURL;
        }
        @Override
        public InputStream getInputStream() throws IOException {
          return includedURL.openConnection().getInputStream();
        }
        @Override
        public Position getIncludePosition() {
          return includePosition;
        }
        public String toString() {
          return "[include:"+includePosition+"]"+super.toString();
        }
      };
      
      return new Pos();
    } else {
      return null;
    }
  }

  @Override
  public void dump(PrintStream ps) {
    // TODO Auto-generated method stub

  }

}
