package org.fxmisc.richtext;

import java.util.function.IntFunction;

import javafx.scene.Node;
import javafx.scene.control.Label;

import org.reactfx.collection.LiveList;
import org.reactfx.value.Val;

public class LineNumberFactory implements IntFunction<Node> {

    private static final String STYLESHEET = LineNumberFactory.class.getResource("lineno.css").toExternalForm();

    public static IntFunction<Node> get(StyledTextArea<?> area,String customStylesheet) {
        return new LineNumberFactory(area,customStylesheet);
    }
    public static IntFunction<Node> get(StyledTextArea<?> area) {
        return new LineNumberFactory(area, STYLESHEET);
    }

    public static IntFunction<Node> get(StyledTextArea<?> area,IntFunction<String> format) {
        return new LineNumberFactory(area,format,STYLESHEET);
    }
    public static IntFunction<Node> get(StyledTextArea<?> area,IntFunction<String> format,String customStylesheet) {
        return new LineNumberFactory(area,format,customStylesheet);
    }
    private final Val<Integer> nParagraphs;
    private final String stylesheet;
    private final IntFunction<String> format;

    private LineNumberFactory(StyledTextArea<?> area, String stylesheet) {
        nParagraphs = LiveList.sizeOf(area.getParagraphs());
        this.format = (digits -> "%0" + digits + "d");
        this.stylesheet = stylesheet;
    }
    private LineNumberFactory(StyledTextArea<?> area, IntFunction<String> format, String stylesheet) {
        nParagraphs = LiveList.sizeOf(area.getParagraphs());
        this.format = format;
        this.stylesheet = stylesheet;
    }

    @Override
    public Node apply(int idx) {
        Label lineNo = new Label();
        lineNo.getStyleClass().add("lineno");
        lineNo.getStylesheets().add(stylesheet);

        // When removed from the scene, bind label's text to constant "", which
        // is a fake binding that consumes no resources, instead of staying
        // bound to area's paragraphs.
        lineNo.textProperty().bind(Val.flatMap(
                lineNo.sceneProperty(),
                scene -> scene != null
                        ? nParagraphs.map(n -> format(idx+1, n))
                        : Val.constant("")));
        return lineNo;
    }

    private String format(int x, int max) {
        int digits = (int) Math.floor(Math.log10(max)) + 1;
        return String.format(format.apply(digits), x);
    }
}

@@ -303,16 +303,28 @@
 ESHEET =
+%0A           
  LineNum
@@ -451,94 +451,47 @@
 area
-,String customStylesheet) %7B%0A        return new LineNumberFactory(area,customStylesheet
+) %7B%0A        return get(area, STYLESHEET
 );%0A 
@@ -487,32 +487,33 @@
 LESHEET);%0A    %7D%0A
+%0A
     public stati
@@ -528,32 +528,45 @@
 ction%3CNode%3E get(
+%0A            
 StyledTextArea%3C?
@@ -575,65 +575,121 @@
 area
-) %7B%0A        return new LineNumberFactory(area, STYLESHEET
+,%0A            String customStylesheet) %7B%0A        return get(area, digits -%3E %22%250%22 + digits + %22d%22, customStylesheet
 );%0A 
@@ -726,32 +726,45 @@
 ction%3CNode%3E get(
+%0A            
 StyledTextArea%3C?
@@ -762,32 +762,45 @@
 extArea%3C?%3E area,
+%0A            
 IntFunction%3CStri
@@ -832,42 +832,26 @@
 urn 
-new LineNumberFactory
+get
 (area,
+ 
 format,
+ 
 STYL
@@ -861,24 +861,25 @@
 EET);%0A    %7D%0A
+%0A
     public s
@@ -898,32 +898,45 @@
 ction%3CNode%3E get(
+%0A            
 StyledTextArea%3C?
@@ -942,16 +942,29 @@
 ?%3E area,
+%0A            
 IntFunct
@@ -982,16 +982,29 @@
  format,
+%0A            
 String c
@@ -1064,23 +1064,25 @@
 ry(area,
+ 
 format,
+ 
 customSt
@@ -1090,32 +1090,33 @@
 lesheet);%0A    %7D%0A
+%0A
     private fina
@@ -1261,243 +1261,21 @@
 ory(
-StyledTextArea%3C?%3E area, String stylesheet) %7B%0A        nParagraphs = LiveList.sizeOf(area.getParagraphs());%0A        this.format = (digits -%3E %22%250%22 + digits + %22d%22);%0A        this.stylesheet = stylesheet;%0A    %7D%0A    private LineNumberFactory(
+%0A            
 Styl
@@ -1293,16 +1293,28 @@
 ?%3E area,
+%0A           
  IntFunc
@@ -1333,16 +1333,28 @@
  format,
+%0A           
  String 
@@ -1759,14 +1759,8 @@
  %22%22,
- which
 %0A   
@@ -1766,16 +1766,22 @@
       //
+ which
  is a fa
@@ -1833,16 +1833,8 @@
 d of
- staying
 %0A   
@@ -1840,16 +1840,24 @@
       //
+ staying
  bound t

Clean up formatting and factory methods in LineNumberFactory.