1var systemLineBreak = require('os').EOL;
2
3var override = require('../utils/override');
4
5var Breaks = {
6  AfterAtRule: 'afterAtRule',
7  AfterBlockBegins: 'afterBlockBegins',
8  AfterBlockEnds: 'afterBlockEnds',
9  AfterComment: 'afterComment',
10  AfterProperty: 'afterProperty',
11  AfterRuleBegins: 'afterRuleBegins',
12  AfterRuleEnds: 'afterRuleEnds',
13  BeforeBlockEnds: 'beforeBlockEnds',
14  BetweenSelectors: 'betweenSelectors'
15};
16
17var BreakWith = {
18  CarriageReturnLineFeed: '\r\n',
19  LineFeed: '\n',
20  System: systemLineBreak
21};
22
23var IndentWith = {
24  Space: ' ',
25  Tab: '\t'
26};
27
28var Spaces = {
29  AroundSelectorRelation: 'aroundSelectorRelation',
30  BeforeBlockBegins: 'beforeBlockBegins',
31  BeforeValue: 'beforeValue'
32};
33
34var DEFAULTS = {
35  breaks: breaks(false),
36  breakWith: BreakWith.System,
37  indentBy: 0,
38  indentWith: IndentWith.Space,
39  spaces: spaces(false),
40  wrapAt: false,
41  semicolonAfterLastProperty: false
42};
43
44var BEAUTIFY_ALIAS = 'beautify';
45var KEEP_BREAKS_ALIAS = 'keep-breaks';
46
47var OPTION_SEPARATOR = ';';
48var OPTION_NAME_VALUE_SEPARATOR = ':';
49var HASH_VALUES_OPTION_SEPARATOR = ',';
50var HASH_VALUES_NAME_VALUE_SEPARATOR = '=';
51
52var FALSE_KEYWORD_1 = 'false';
53var FALSE_KEYWORD_2 = 'off';
54var TRUE_KEYWORD_1 = 'true';
55var TRUE_KEYWORD_2 = 'on';
56
57function breaks(value) {
58  var breakOptions = {};
59
60  breakOptions[Breaks.AfterAtRule] = value;
61  breakOptions[Breaks.AfterBlockBegins] = value;
62  breakOptions[Breaks.AfterBlockEnds] = value;
63  breakOptions[Breaks.AfterComment] = value;
64  breakOptions[Breaks.AfterProperty] = value;
65  breakOptions[Breaks.AfterRuleBegins] = value;
66  breakOptions[Breaks.AfterRuleEnds] = value;
67  breakOptions[Breaks.BeforeBlockEnds] = value;
68  breakOptions[Breaks.BetweenSelectors] = value;
69
70  return breakOptions;
71}
72
73function spaces(value) {
74  var spaceOptions = {};
75
76  spaceOptions[Spaces.AroundSelectorRelation] = value;
77  spaceOptions[Spaces.BeforeBlockBegins] = value;
78  spaceOptions[Spaces.BeforeValue] = value;
79
80  return spaceOptions;
81}
82
83function formatFrom(source) {
84  if (source === undefined || source === false) {
85    return false;
86  }
87
88  if (typeof source == 'object' && 'breakWith' in source) {
89    source = override(source, { breakWith: mapBreakWith(source.breakWith) });
90  }
91
92  if (typeof source == 'object' && 'indentBy' in source) {
93    source = override(source, { indentBy: parseInt(source.indentBy) });
94  }
95
96  if (typeof source == 'object' && 'indentWith' in source) {
97    source = override(source, { indentWith: mapIndentWith(source.indentWith) });
98  }
99
100  if (typeof source == 'object') {
101    return override(DEFAULTS, source);
102  }
103
104  if (typeof source == 'object') {
105    return override(DEFAULTS, source);
106  }
107
108  if (typeof source == 'string' && source == BEAUTIFY_ALIAS) {
109    return override(DEFAULTS, {
110      breaks: breaks(true),
111      indentBy: 2,
112      spaces: spaces(true)
113    });
114  }
115
116  if (typeof source == 'string' && source == KEEP_BREAKS_ALIAS) {
117    return override(DEFAULTS, {
118      breaks: {
119        afterAtRule: true,
120        afterBlockBegins: true,
121        afterBlockEnds: true,
122        afterComment: true,
123        afterRuleEnds: true,
124        beforeBlockEnds: true
125      }
126    });
127  }
128
129  if (typeof source == 'string') {
130    return override(DEFAULTS, toHash(source));
131  }
132
133  return DEFAULTS;
134}
135
136function toHash(string) {
137  return string
138    .split(OPTION_SEPARATOR)
139    .reduce(function (accumulator, directive) {
140      var parts = directive.split(OPTION_NAME_VALUE_SEPARATOR);
141      var name = parts[0];
142      var value = parts[1];
143
144      if (name == 'breaks' || name == 'spaces') {
145        accumulator[name] = hashValuesToHash(value);
146      } else if (name == 'indentBy' || name == 'wrapAt') {
147        accumulator[name] = parseInt(value);
148      } else if (name == 'indentWith') {
149        accumulator[name] = mapIndentWith(value);
150      } else if (name == 'breakWith') {
151        accumulator[name] = mapBreakWith(value);
152      }
153
154      return accumulator;
155    }, {});
156}
157
158function hashValuesToHash(string) {
159  return string
160    .split(HASH_VALUES_OPTION_SEPARATOR)
161    .reduce(function (accumulator, directive) {
162      var parts = directive.split(HASH_VALUES_NAME_VALUE_SEPARATOR);
163      var name = parts[0];
164      var value = parts[1];
165
166      accumulator[name] = normalizeValue(value);
167
168      return accumulator;
169    }, {});
170}
171
172
173function normalizeValue(value) {
174  switch (value) {
175    case FALSE_KEYWORD_1:
176    case FALSE_KEYWORD_2:
177      return false;
178    case TRUE_KEYWORD_1:
179    case TRUE_KEYWORD_2:
180      return true;
181    default:
182      return value;
183  }
184}
185
186function mapBreakWith(value) {
187  switch (value) {
188    case 'windows':
189    case 'crlf':
190    case BreakWith.CarriageReturnLineFeed:
191      return BreakWith.CarriageReturnLineFeed;
192    case 'unix':
193    case 'lf':
194    case BreakWith.LineFeed:
195      return BreakWith.LineFeed;
196    default:
197      return systemLineBreak;
198  }
199}
200
201function mapIndentWith(value) {
202  switch (value) {
203    case 'space':
204      return IndentWith.Space;
205    case 'tab':
206      return IndentWith.Tab;
207    default:
208      return value;
209  }
210}
211
212module.exports = {
213  Breaks: Breaks,
214  Spaces: Spaces,
215  formatFrom: formatFrom
216};
217