1 module hunt.time.format.PadPrinterParserDecorator;
2 
3 import hunt.time.Exceptions;
4 
5 import hunt.time.format.DateTimeParseContext;
6 import hunt.time.format.DateTimePrinterParser;
7 import hunt.time.format.DateTimePrintContext;
8 import hunt.time.temporal.TemporalField;
9 import hunt.util.StringBuilder;
10 
11 import hunt.Exceptions;
12 
13 import std.conv;
14 
15 //-----------------------------------------------------------------------
16 /**
17  * Pads the output to a fixed width.
18  */
19 static final class PadPrinterParserDecorator : DateTimePrinterParser
20 {
21     private DateTimePrinterParser printerParser;
22     private int padWidth;
23     private char padChar;
24 
25     /**
26      * Constructor.
27      *
28      * @param printerParser  the printer, not null
29      * @param padWidth  the width to pad to, 1 or greater
30      * @param padChar  the pad character
31      */
32     this(DateTimePrinterParser printerParser, int padWidth, char padChar)
33     {
34         // input checked by DateTimeFormatterBuilder
35         this.printerParser = printerParser;
36         this.padWidth = padWidth;
37         this.padChar = padChar;
38     }
39 
40     override public bool format(DateTimePrintContext context, StringBuilder buf)
41     {
42         int preLen = buf.length();
43         if (printerParser.format(context, buf) == false)
44         {
45             return false;
46         }
47         int len = buf.length() - preLen;
48         if (len > padWidth)
49         {
50             throw new DateTimeException("Cannot print as output of " ~ len.to!string
51                     ~ " characters exceeds pad width of " ~ padWidth.to!string);
52         }
53         for (int i = 0; i < padWidth - len; i++)
54         {
55             buf.insert(preLen, padChar);
56         }
57         return true;
58     }
59 
60     override public int parse(DateTimeParseContext context, string text, int position)
61     {
62         // cache context before changed by decorated parser
63         bool strict = context.isStrict();
64         // parse
65         if (position > text.length)
66         {
67             throw new IndexOutOfBoundsException();
68         }
69         if (position == text.length)
70         {
71             return ~position; // no more characters _in the string
72         }
73         int endPos = position + padWidth;
74         if (endPos > text.length)
75         {
76             if (strict)
77             {
78                 return ~position; // not enough characters _in the string to meet the parse width
79             }
80             endPos = cast(int)(text.length);
81         }
82         int pos = position;
83         while (pos < endPos && context.charEquals(text[pos], padChar))
84         {
85             pos++;
86         }
87         text = text[0 .. endPos];
88         int resultPos = printerParser.parse(context, text, pos);
89         if (resultPos != endPos && strict)
90         {
91             return ~(position + pos); // parse of decorated field didn't parse to the end
92         }
93         return resultPos;
94     }
95 
96     override public string toString()
97     {
98         return "Pad(" ~ printerParser.toString ~ "," ~ padWidth.to!string ~ (padChar == ' '
99                 ? ")" : ",'" ~ padChar ~ "')");
100     }
101 }