package com.dua3.utility.text;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;

public class Text extends AbstractList<String> {

    private final List<String> lines;

    public static Text load(Path path, Charset cs) throws IOException {
        try (BufferedReader reader = Files.newBufferedReader(path, cs)) {
            Text text = new Text();
            for (;;) {
                String line = reader.readLine();
                if (line == null)
                    break;
                text.addUnchecked(line);
            }
            return text;
        }
    }

    public Text(List<String> lines) {
        this.lines = new ArrayList<>(lines);
    }

    public Text() {
        lines = new ArrayList<>();
    }

    @Override
    public String get(int index) {
        return lines.get(index);
    }

    @Override
    public int size() {
        return lines.size();
    }

    @Override
    public boolean add(String line) {
        checkNoLineBreaks(line);
        return addUnchecked(line);
    }

    private boolean addUnchecked(String line) {
        return lines.add(line);
    }

    public boolean addText(String text) {
        for (String s: text.split("\n")) {
            addUnchecked(s);
        }
        return true;
    }

    private static void checkNoLineBreaks(String line) {
        if (containsLineBreaks(line)) {
            throw new IllegalArgumentException("line must not contains linebreaks");
        }
    }

    private static boolean containsLineBreaks(String line) {
        return line.indexOf('\n')>=0;
    }
}

@@ -255,16 +255,56 @@
 .List;%0A%0A
+import com.dua3.utility.lang.LangUtil;%0A%0A
 public c
@@ -361,33 +361,165 @@
 ate 
-final List%3CString%3E lines;
+static final char NEWLINE = '%5Cn';%0A    private static final String NEWLINE_STR = %22%22 + '%5Cn';%0A%0A    public static Text empty() %7B%0A        return new Text();%0A    %7D
 %0A%0A  
@@ -803,16 +803,18 @@
 == null)
+ %7B
 %0A       
@@ -833,16 +833,34 @@
  break;%0A
+                %7D%0A
         
@@ -957,37 +957,56 @@
    p
-ublic Text(List%3C
+rivate static void checkNoLineBreaks(
 String
-%3E
  line
-s
 ) %7B%0A
@@ -1017,267 +1017,433 @@
     
-this.lines = new ArrayList%3C%3E(lines);%0A    %7D%0A%0A    public Text() %7B%0A        lines = new ArrayList%3C%3E();%0A    %7D%0A%0A    @Override%0A    public String get(int index) %7B%0A        return lines.get(index);%0A    %7D%0A%0A    @Override%0A    public int size() %7B
+if (containsLineBreaks(line)) %7B%0A            throw new IllegalArgumentException(%22line must not contain linebreaks%22);%0A        %7D%0A    %7D%0A%0A    private static boolean containsLineBreaks(String line) %7B%0A        return line.indexOf(NEWLINE) %3E= 0;%0A    %7D%0A%0A    private final List%3CString%3E lines;%0A%0A    public Text() %7B%0A        lines = new ArrayList%3C%3E();
 %0A    
+%7D%0A%0A
     
-return lines.size(
+public Text(List%3CString%3E lines) %7B%0A        this.lines = new ArrayList%3C%3E(lines
 );%0A 
@@ -1580,22 +1580,21 @@
 %7D%0A%0A    p
-rivate
+ublic
  boolean
@@ -1601,29 +1601,191 @@
  add
-Unchecked(String line
+Text(String text) %7B%0A        for (String s : text.split(NEWLINE_STR)) %7B%0A            addUnchecked(s);%0A        %7D%0A        return true;%0A    %7D%0A%0A    @Override%0A    public String get(int index
 ) %7B%0A
@@ -1809,16 +1809,17 @@
 nes.
-add(line
+get(index
 );%0A 
@@ -1839,120 +1839,256 @@
 lic 
-boolean addText(String text) %7B%0A        for (String s: text.split(%22%5Cn%22)) %7B%0A            addUnchecked(s
+Text region(int begin, int end) %7B%0A        LangUtil.check(begin %3E= 0 && begin %3C end && end %3C= lines.size(), %22invalid region from %7B%7D to %7B%7D%22, begin, end);%0A        return new Text(lines.subList(begin, end)
 );%0A    
+%7D%0A%0A
     
-%7D
+@Override%0A    public int size() %7B
 %0A   
@@ -2091,36 +2091,44 @@
 %0A        return 
-true
+lines.size()
 ;%0A    %7D%0A%0A    pri
@@ -2128,97 +2128,154 @@
     
-private static void checkNoLineBreaks(String line) %7B%0A        if (containsLineBreaks(
+@Override%0A    public String toString() %7B%0A        StringBuilder sb = new StringBuilder();%0A        String sep = %22%22;%0A        for (String line : 
 line
-)
+s
 ) %7B%0A
@@ -2290,90 +2290,107 @@
     
-throw new IllegalArgumentException(%22line must not contains linebreaks%22);%0A        %7D
+sb.append(sep).append(line);%0A            sep = NEWLINE_STR;%0A        %7D%0A        return sb.toString();
 %0A   
@@ -2401,39 +2401,32 @@
     private 
-static 
 boolean 
 containsLine
@@ -2413,34 +2413,28 @@
 boolean 
-containsLineBreaks
+addUnchecked
 (String 
@@ -2464,25 +2464,19 @@
 line
-.indexOf('%5Cn')%3E=0
+s.add(line)
 ;%0A  

toString(), empty(), region(int,int), cleanup source