1   package org.daisy.pipeline.braille.common;
2   
3   import java.util.Collections;
4   import java.util.Locale;
5   
6   import org.daisy.braille.css.SimpleInlineStyle;
7   import org.daisy.pipeline.braille.css.CSSStyledText;
8   
9   /**
10   * Hyphenation means morphological breaking within <em>words</em>. However this class is
11   * not only responsible for providing hyphenation opportunities, but all soft wrap
12   * opportunities (including but not restricted to those defined by the Unicode line
13   * breaking rules [UAX14]).
14   */
15  public interface Hyphenator extends Transform {
16  	
17  	/**
18  	 * Indicate all soft wrap opportunities by inserting soft hyphens and zero width
19  	 * spaces. Don't add new soft wrap opportunities to words that already have a soft
20  	 * hyphen or zero width space in them. Soft wrap opportunities at white space may also
21  	 * be omitted. Apart from the insertion of these special characters no other
22  	 * transformations are allowed. This means that non-standard hyphenation can not be
23  	 * supported through this interface.
24  	 */
25  	public FullHyphenator asFullHyphenator() throws UnsupportedOperationException;
26  	
27  	/**
28  	 * Break the input into lines of a preferred and maximal length. Transformations such
29  	 * as non-standard hyphenation are allowed.
30  	 *
31  	 * A {@link LineBreaker} is not required to do any special white space processing, but
32  	 * it may.
33  	 *
34  	 * If the {@link FullHyphenator} returned by {@link #asFullHyphenator()} throws a {@link
35  	 * NonStandardHyphenationException}, the {@link #asLineBreaker()} method must not throw a {@link
36  	 * UnsupportedOperationException}.
37  	 */
38  	public LineBreaker asLineBreaker() throws UnsupportedOperationException;
39  	
40  	/* ------------------ */
41  	/* asFullHyphenator() */
42  	/* ------------------ */
43  	
44  	public interface FullHyphenator {
45  		
46  		public Iterable<CSSStyledText> transform(Iterable<CSSStyledText> text) throws NonStandardHyphenationException;
47  		
48  		/**
49  		 * This method is intended to be overridden with a more optimal implementation.
50  		 */
51  		public default String transform(String text, SimpleInlineStyle style, Locale language)
52  				throws NonStandardHyphenationException {
53  			return transform(Collections.singleton(new CSSStyledText(text, style, language)))
54  			       .iterator().next().getText();
55  		}
56  	}
57  	
58  	/* --------------- */
59  	/* asLineBreaker() */
60  	/* --------------- */
61  	
62  	public interface LineBreaker {
63  		
64  		public LineIterator transform(String input, Locale language);
65  		
66  	}
67  	
68  	/**
69  	 * Thrown by {@link FullHyphenator} if non-standard breaks are present.
70  	 */
71  	@SuppressWarnings("serial")
72  	public class NonStandardHyphenationException extends RuntimeException {
73  
74  		public NonStandardHyphenationException() {
75  			super();
76  		}
77  
78  		public NonStandardHyphenationException(Throwable cause) {
79  			super(cause);
80  		}
81  	}
82  
83  	/* ------------ */
84  	/* LineIterator */
85  	/* ------------ */
86  	
87  	public interface LineIterator {
88  		
89  		/**
90  		 * Returns true if there is remaining text to make a new line of.
91  		 */
92  		public boolean hasNext();
93  		
94  		/**
95  		 * Get the next line of text, with a length as close as possible to, but not
96  		 * exceding `limit` characters, breaking a word if needed. The line does not
97  		 * include a possible hyphen character (see {@link lineHasHyphen()}). `limit` must
98  		 * be greater than 0. If `force` is true, may not return an empty string. If
99  		 * `allowHyphens` is false, breaking words is not permitted unless `force` is true
100 		 * and an empty string would otherwise be returned. Must throw an exception if
101 		 * there is no remaining text to make a new line of.
102 		 */
103 		public String nextLine(int limit, boolean force, boolean allowHyphens);
104 		public String nextLine(int limit, boolean force);
105 		
106 		/**
107 		 * Whether or not a hyphen character should be inserted at the end of
108 		 * the current line to indicate a word break. Must throw an exception
109 		 * if `nextLine` hasn't been called yet.
110 		 */
111 		public boolean lineHasHyphen();
112 		
113 		public String remainder();
114 		
115 		/**
116 		 * Set a checkpoint to which the iterator can be `reset` later.
117 		 */
118 		public void mark();
119 		
120 		/**
121 		 * Roll back to a checkpoint previously set with `mark`, or to the
122 		 * beginning if `mark` hasn't been called yet.
123 		 */
124 		public void reset();
125 		
126 	}
127 }