/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/

#import "CDVGlobalization.h"

@implementation CDVGlobalization

- (void)pluginInitialize
{
currentLocale = CFLocaleCopyCurrent();
}

- (void)getPreferredLanguage:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* result = nil;

// Source: http://stackoverflow.com/questions/3910244/getting-current-device-language-in-ios
// (should be OK)
NSString* language = [[NSLocale preferredLanguages] objectAtIndex:0];

if (language) {
//Format to match other devices
if(language.length <= 2) {
NSLocale* locale = [NSLocale currentLocale];
NSString* localeId = [locale localeIdentifier];
NSRange underscoreIndex = [localeId rangeOfString:@"_" options:NSBackwardsSearch];
NSRange atSignIndex = [localeId rangeOfString:@"@"];
if (underscoreIndex.location != NSNotFound) {
//If localeIdentifier did not contain @, i.e. did not have calendar other than Gregoarian selected
if(atSignIndex.length == 0)
language = [NSString stringWithFormat:@"%@%@", language, [localeId substringFromIndex:underscoreIndex.location]];
else {
NSRange localeRange = NSMakeRange(underscoreIndex.location, atSignIndex.location-underscoreIndex.location);
language = [NSString stringWithFormat:@"%@%@", language, [localeId substringWithRange:localeRange]];
}
}
}

language = [language stringByReplacingOccurrencesOfString:@"_" withString:@"-"];

NSDictionary* dictionary = [NSDictionary dictionaryWithObject:language forKey:@"value"];

result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsDictionary:dictionary];
} else {
// TBD is this ever expected to happen?
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
[dictionary setValue:@"Unknown error" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
}

- (void)getLocaleName:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* result = nil;
NSDictionary* dictionary = nil;

NSLocale* locale = [NSLocale currentLocale];

if (locale) {
NSString *localeIdentifier = [[locale localeIdentifier] stringByReplacingOccurrencesOfString:@"_" withString:@"-"];

dictionary = [NSDictionary dictionaryWithObject:localeIdentifier forKey:@"value"];

result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
} else {
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
[dictionary setValue:@"Unknown error" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
}

- (void)dateToString:(CDVInvokedUrlCommand*)command
{
CFDateFormatterStyle style = kCFDateFormatterShortStyle;
CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle;
CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle;
NSDate* date = nil;
NSString* dateString = nil;
CDVPluginResult* result = nil;

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

id milliseconds = [options valueForKey:@"date"];

if (milliseconds && [milliseconds isKindOfClass:[NSNumber class]]) {
// get the number of seconds since 1970 and create the date object
date = [NSDate dateWithTimeIntervalSince1970:[milliseconds doubleValue] / 1000];
}

// see if any options have been specified
id items = [options valueForKey:@"options"];
if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
NSEnumerator* enumerator = [items keyEnumerator];
id key;

// iterate through all the options
while ((key = [enumerator nextObject])) {
id item = [items valueForKey:key];

// make sure that only string values are present
if ([item isKindOfClass:[NSString class]]) {
// get the desired format length
if ([key isEqualToString:@"formatLength"]) {
if ([item isEqualToString:@"short"]) {
style = kCFDateFormatterShortStyle;
} else if ([item isEqualToString:@"medium"]) {
style = kCFDateFormatterMediumStyle;
} else if ([item isEqualToString:@"long"]) {
style = kCFDateFormatterLongStyle;
} else if ([item isEqualToString:@"full"]) {
style = kCFDateFormatterFullStyle;
}
}
// get the type of date and time to generate
else if ([key isEqualToString:@"selector"]) {
if ([item isEqualToString:@"date"]) {
dateStyle = style;
timeStyle = kCFDateFormatterNoStyle;
} else if ([item isEqualToString:@"time"]) {
dateStyle = kCFDateFormatterNoStyle;
timeStyle = style;
} else if ([item isEqualToString:@"date and time"]) {
dateStyle = style;
timeStyle = style;
}
}
}
}
}

// create the formatter using the user's current default locale and formats for dates and times
CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
currentLocale,
dateStyle,
timeStyle);
// if we have a valid date object then call the formatter
if (date) {
dateString = (__bridge_transfer NSString*)CFDateFormatterCreateStringWithDate(kCFAllocatorDefault,
formatter,
(__bridge CFDateRef)date);
}

// if the date was converted to a string successfully then return the result
if (dateString) {
NSDictionary* dictionary = [NSDictionary dictionaryWithObject:dateString forKey:@"value"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
}
// error
else {
// DLog(@"GlobalizationCommand dateToString unable to format %@", [date description]);
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_FORMATTING_ERROR] forKey:@"code"];
[dictionary setValue:@"Formatting error" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];

CFRelease(formatter);
}

- (void)stringToDate:(CDVInvokedUrlCommand*)command
{
CFDateFormatterStyle style = kCFDateFormatterShortStyle;
CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle;
CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle;
CDVPluginResult* result = nil;
NSString* dateString = nil;
NSDateComponents* comps = nil;

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

// get the string that is to be parsed for a date
id ms = [options valueForKey:@"dateString"];

if (ms && [ms isKindOfClass:[NSString class]]) {
dateString = ms;
}

// see if any options have been specified
id items = [options valueForKey:@"options"];
if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
NSEnumerator* enumerator = [items keyEnumerator];
id key;

// iterate through all the options
while ((key = [enumerator nextObject])) {
id item = [items valueForKey:key];

// make sure that only string values are present
if ([item isKindOfClass:[NSString class]]) {
// get the desired format length
if ([key isEqualToString:@"formatLength"]) {
if ([item isEqualToString:@"short"]) {
style = kCFDateFormatterShortStyle;
} else if ([item isEqualToString:@"medium"]) {
style = kCFDateFormatterMediumStyle;
} else if ([item isEqualToString:@"long"]) {
style = kCFDateFormatterLongStyle;
} else if ([item isEqualToString:@"full"]) {
style = kCFDateFormatterFullStyle;
}
}
// get the type of date and time to generate
else if ([key isEqualToString:@"selector"]) {
if ([item isEqualToString:@"date"]) {
dateStyle = style;
timeStyle = kCFDateFormatterNoStyle;
} else if ([item isEqualToString:@"time"]) {
dateStyle = kCFDateFormatterNoStyle;
timeStyle = style;
} else if ([item isEqualToString:@"date and time"]) {
dateStyle = style;
timeStyle = style;
}
}
}
}
}

// get the user's default settings for date and time formats
CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
currentLocale,
dateStyle,
timeStyle);

// set the parsing to be more lenient
CFDateFormatterSetProperty(formatter, kCFDateFormatterIsLenient, kCFBooleanTrue);

// parse tha date and time string
CFDateRef date = CFDateFormatterCreateDateFromString(kCFAllocatorDefault,
formatter,
(__bridge CFStringRef)dateString,
NULL);

// if we were able to parse the date then get the date and time components
if (date != NULL) {
NSCalendar* calendar = [NSCalendar currentCalendar];

unsigned unitFlags = NSCalendarUnitYear |
NSCalendarUnitMonth |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond;

comps = [calendar components:unitFlags fromDate:(__bridge NSDate*)date];
CFRelease(date);
}

// put the various elements of the date and time into a dictionary
if (comps != nil) {
NSArray* keys = [NSArray arrayWithObjects:@"year", @"month", @"day", @"hour", @"minute", @"second", @"millisecond", nil];
NSArray* values = [NSArray arrayWithObjects:[NSNumber numberWithInteger:[comps year]],
[NSNumber numberWithInteger:[comps month] - 1],
[NSNumber numberWithInteger:[comps day]],
[NSNumber numberWithInteger:[comps hour]],
[NSNumber numberWithInteger:[comps minute]],
[NSNumber numberWithInteger:[comps second]],
[NSNumber numberWithInteger:0], /* iOS does not provide milliseconds */
nil];

NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
}
// error
else {
// Dlog(@"GlobalizationCommand stringToDate unable to parse %@", dateString);
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_PARSING_ERROR] forKey:@"code"];
[dictionary setValue:@"unable to parse" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];

CFRelease(formatter);
}

- (void)getDatePattern:(CDVInvokedUrlCommand*)command
{
CFDateFormatterStyle style = kCFDateFormatterShortStyle;
CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle;
CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle;
CDVPluginResult* result = nil;

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

// see if any options have been specified
id items = [options valueForKey:@"options"];

if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
NSEnumerator* enumerator = [items keyEnumerator];
id key;

// iterate through all the options
while ((key = [enumerator nextObject])) {
id item = [items valueForKey:key];

// make sure that only string values are present
if ([item isKindOfClass:[NSString class]]) {
// get the desired format length
if ([key isEqualToString:@"formatLength"]) {
if ([item isEqualToString:@"short"]) {
style = kCFDateFormatterShortStyle;
} else if ([item isEqualToString:@"medium"]) {
style = kCFDateFormatterMediumStyle;
} else if ([item isEqualToString:@"long"]) {
style = kCFDateFormatterLongStyle;
} else if ([item isEqualToString:@"full"]) {
style = kCFDateFormatterFullStyle;
}
}
// get the type of date and time to generate
else if ([key isEqualToString:@"selector"]) {
if ([item isEqualToString:@"date"]) {
dateStyle = style;
timeStyle = kCFDateFormatterNoStyle;
} else if ([item isEqualToString:@"time"]) {
dateStyle = kCFDateFormatterNoStyle;
timeStyle = style;
} else if ([item isEqualToString:@"date and time"]) {
dateStyle = style;
timeStyle = style;
}
}
}
}
}

// get the user's default settings for date and time formats
CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
currentLocale,
dateStyle,
timeStyle);

// get the date pattern to apply when formatting and parsing
CFStringRef datePattern = CFDateFormatterGetFormat(formatter);
// get the user's current time zone information
CFTimeZoneRef timezone = (CFTimeZoneRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTimeZone);

// put the pattern and time zone information into the dictionary
if ((datePattern != nil) && (timezone != nil)) {
NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"timezone", @"iana_timezone", @"utc_offset", @"dst_offset", nil];
NSArray* values = [NSArray arrayWithObjects:((__bridge NSString*)datePattern),
[((__bridge NSTimeZone*)timezone)abbreviation],
[((__bridge NSTimeZone*)timezone)name],
[NSNumber numberWithLong:[((__bridge NSTimeZone*)timezone)secondsFromGMT]],
[NSNumber numberWithDouble:[((__bridge NSTimeZone*)timezone)daylightSavingTimeOffset]],
nil];

NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
}
// error
else {
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"];
[dictionary setValue:@"Pattern error" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];

if (timezone) {
CFRelease(timezone);
}
CFRelease(formatter);
}

- (void)getDateNames:(CDVInvokedUrlCommand*)command
{
int style = CDV_FORMAT_LONG;
int selector = CDV_SELECTOR_MONTHS;
CFStringRef dataStyle = kCFDateFormatterMonthSymbols;
CDVPluginResult* result = nil;

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

// see if any options have been specified
id items = [options valueForKey:@"options"];

if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
NSEnumerator* enumerator = [items keyEnumerator];
id key;

// iterate through all the options
while ((key = [enumerator nextObject])) {
id item = [items valueForKey:key];

// make sure that only string values are present
if ([item isKindOfClass:[NSString class]]) {
// get the desired type of name
if ([key isEqualToString:@"type"]) {
if ([item isEqualToString:@"narrow"]) {
style = CDV_FORMAT_SHORT;
} else if ([item isEqualToString:@"wide"]) {
style = CDV_FORMAT_LONG;
}
}
// determine if months or days are needed
else if ([key isEqualToString:@"item"]) {
if ([item isEqualToString:@"months"]) {
selector = CDV_SELECTOR_MONTHS;
} else if ([item isEqualToString:@"days"]) {
selector = CDV_SELECTOR_DAYS;
}
}
}
}
}

CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
currentLocale,
kCFDateFormatterFullStyle,
kCFDateFormatterFullStyle);

if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_LONG)) {
dataStyle = kCFDateFormatterMonthSymbols;
} else if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_SHORT)) {
dataStyle = kCFDateFormatterShortMonthSymbols;
} else if ((selector == CDV_SELECTOR_DAYS) && (style == CDV_FORMAT_LONG)) {
dataStyle = kCFDateFormatterWeekdaySymbols;
} else if ((selector == CDV_SELECTOR_DAYS) && (style == CDV_FORMAT_SHORT)) {
dataStyle = kCFDateFormatterShortWeekdaySymbols;
}

CFArrayRef names = (CFArrayRef)CFDateFormatterCopyProperty(formatter, dataStyle);

if (names) {
NSDictionary* dictionary = [NSDictionary dictionaryWithObject:((__bridge NSArray*)names) forKey:@"value"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
CFRelease(names);
}
// error
else {
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
[dictionary setValue:@"Unknown error" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];

CFRelease(formatter);
}

- (void)isDayLightSavingsTime:(CDVInvokedUrlCommand*)command
{
NSDate* date = nil;
CDVPluginResult* result = nil;

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

id milliseconds = [options valueForKey:@"date"];

if (milliseconds && [milliseconds isKindOfClass:[NSNumber class]]) {
// get the number of seconds since 1970 and create the date object
date = [NSDate dateWithTimeIntervalSince1970:[milliseconds doubleValue] / 1000];
}

if (date) {
// get the current calendar for the user and check if the date is using DST
NSCalendar* calendar = [NSCalendar currentCalendar];
NSTimeZone* timezone = [calendar timeZone];
NSNumber* dst = [NSNumber numberWithBool:[timezone isDaylightSavingTimeForDate:date]];

NSDictionary* dictionary = [NSDictionary dictionaryWithObject:dst forKey:@"dst"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
}
// error
else {
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
[dictionary setValue:@"Unknown error" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
}

- (void)getFirstDayOfWeek:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* result = nil;

NSCalendar* calendar = [NSCalendar autoupdatingCurrentCalendar];

NSNumber* day = [NSNumber numberWithInteger:[calendar firstWeekday]];

if (day) {
NSDictionary* dictionary = [NSDictionary dictionaryWithObject:day forKey:@"value"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
}
// error
else {
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
[dictionary setValue:@"Unknown error" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
}

- (void)numberToString:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* result = nil;
CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle;
NSNumber* number = nil;

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

id value = [options valueForKey:@"number"];

if (value && [value isKindOfClass:[NSNumber class]]) {
number = (NSNumber*)value;
}

// see if any options have been specified
id items = [options valueForKey:@"options"];
if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
NSEnumerator* enumerator = [items keyEnumerator];
id key;

// iterate through all the options
while ((key = [enumerator nextObject])) {
id item = [items valueForKey:key];

// make sure that only string values are present
if ([item isKindOfClass:[NSString class]]) {
// get the desired style of formatting
if ([key isEqualToString:@"type"]) {
if ([item isEqualToString:@"percent"]) {
style = kCFNumberFormatterPercentStyle;
} else if ([item isEqualToString:@"currency"]) {
style = kCFNumberFormatterCurrencyStyle;
} else if ([item isEqualToString:@"decimal"]) {
style = kCFNumberFormatterDecimalStyle;
}
}
}
}
}

CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
currentLocale,
style);

// get the localized string based upon the locale and user preferences
NSString* numberString = (__bridge_transfer NSString*)CFNumberFormatterCreateStringWithNumber(kCFAllocatorDefault,
formatter,
(__bridge CFNumberRef)number);

if (numberString) {
NSDictionary* dictionary = [NSDictionary dictionaryWithObject:numberString forKey:@"value"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
}
// error
else {
// DLog(@"GlobalizationCommand numberToString unable to format %@", [number stringValue]);
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_FORMATTING_ERROR] forKey:@"code"];
[dictionary setValue:@"Unable to format" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];

CFRelease(formatter);
}

- (void)stringToNumber:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* result = nil;
CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle;
NSString* numberString = nil;
double doubleValue;

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

id value = [options valueForKey:@"numberString"];

if (value && [value isKindOfClass:[NSString class]]) {
numberString = (NSString*)value;
}

// see if any options have been specified
id items = [options valueForKey:@"options"];
if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
NSEnumerator* enumerator = [items keyEnumerator];
id key;

// iterate through all the options
while ((key = [enumerator nextObject])) {
id item = [items valueForKey:key];

// make sure that only string values are present
if ([item isKindOfClass:[NSString class]]) {
// get the desired style of formatting
if ([key isEqualToString:@"type"]) {
if ([item isEqualToString:@"percent"]) {
style = kCFNumberFormatterPercentStyle;
} else if ([item isEqualToString:@"currency"]) {
style = kCFNumberFormatterCurrencyStyle;
} else if ([item isEqualToString:@"decimal"]) {
style = kCFNumberFormatterDecimalStyle;
}
}
}
}
}

CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
currentLocale,
style);

// we need to make this lenient so as to avoid problems with parsing currencies that have non-breaking space characters
if (style == kCFNumberFormatterCurrencyStyle) {
CFNumberFormatterSetProperty(formatter, kCFNumberFormatterIsLenient, kCFBooleanTrue);
}

// parse againist the largest type to avoid data loss
Boolean rc = CFNumberFormatterGetValueFromString(formatter,
(__bridge CFStringRef)numberString,
NULL,
kCFNumberDoubleType,
&doubleValue);

if (rc) {
NSDictionary* dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:doubleValue] forKey:@"value"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
}
// error
else {
// DLog(@"GlobalizationCommand stringToNumber unable to parse %@", numberString);
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_PARSING_ERROR] forKey:@"code"];
[dictionary setValue:@"Unable to parse" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];

CFRelease(formatter);
}

- (void)getNumberPattern:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* result = nil;
CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle;
CFStringRef symbolType = NULL;
NSString* symbol = @"";

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

// see if any options have been specified
id items = [options valueForKey:@"options"];

if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
NSEnumerator* enumerator = [items keyEnumerator];
id key;

// iterate through all the options
while ((key = [enumerator nextObject])) {
id item = [items valueForKey:key];

// make sure that only string values are present
if ([item isKindOfClass:[NSString class]]) {
// get the desired style of formatting
if ([key isEqualToString:@"type"]) {
if ([item isEqualToString:@"percent"]) {
style = kCFNumberFormatterPercentStyle;
} else if ([item isEqualToString:@"currency"]) {
style = kCFNumberFormatterCurrencyStyle;
} else if ([item isEqualToString:@"decimal"]) {
style = kCFNumberFormatterDecimalStyle;
}
}
}
}
}

CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
currentLocale,
style);

NSString* numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter);

if (style == kCFNumberFormatterCurrencyStyle) {
symbolType = kCFNumberFormatterCurrencySymbol;
} else if (style == kCFNumberFormatterPercentStyle) {
symbolType = kCFNumberFormatterPercentSymbol;
}

if (symbolType) {
symbol = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, symbolType);
}

NSString* decimal = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterDecimalSeparator);
NSString* grouping = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterGroupingSeparator);
NSString* posSign = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterPlusSign);
NSString* negSign = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterMinusSign);
NSNumber* fracDigits = (__bridge_transfer NSNumber*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterMinFractionDigits);
NSNumber* roundingDigits = (__bridge_transfer NSNumber*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterRoundingIncrement);

// put the pattern information into the dictionary
if (numberPattern != nil) {
NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"symbol", @"fraction", @"rounding",
@"positive", @"negative", @"decimal", @"grouping", nil];
NSArray* values = [NSArray arrayWithObjects:numberPattern, symbol, fracDigits, roundingDigits,
posSign, negSign, decimal, grouping, nil];
NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
}
// error
else {
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"];
[dictionary setValue:@"Pattern error" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];

CFRelease(formatter);
}

- (void)getCurrencyPattern:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* result = nil;
NSString* currencyCode = nil;
NSString* numberPattern = nil;
NSString* decimal = nil;
NSString* grouping = nil;
int32_t defaultFractionDigits;
double roundingIncrement;
Boolean rc;

NSDictionary* options;

if ([command.arguments count] > 0) {
options = [command argumentAtIndex:0];
}
if (!options) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no options given"];
[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
return;
}

id value = [options valueForKey:@"currencyCode"];

if (value && [value isKindOfClass:[NSString class]]) {
currencyCode = (NSString*)value;
}

// first see if there is base currency info available and fill in the currency_info structure
rc = CFNumberFormatterGetDecimalInfoForCurrencyCode((__bridge CFStringRef)currencyCode, &defaultFractionDigits, &roundingIncrement);

// now set the currency code in the formatter
if (rc) {
CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
currentLocale,
kCFNumberFormatterCurrencyStyle);

CFNumberFormatterSetProperty(formatter, kCFNumberFormatterCurrencyCode, (__bridge CFStringRef)currencyCode);
CFNumberFormatterSetProperty(formatter, kCFNumberFormatterInternationalCurrencySymbol, (__bridge CFStringRef)currencyCode);

numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter);
decimal = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterCurrencyDecimalSeparator);
grouping = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterCurrencyGroupingSeparator);

NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"code", @"fraction", @"rounding",
@"decimal", @"grouping", nil];
NSArray* values = [NSArray arrayWithObjects:numberPattern, currencyCode, [NSNumber numberWithInt:defaultFractionDigits],
[NSNumber numberWithDouble:roundingIncrement], decimal, grouping, nil];
NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
CFRelease(formatter);
}
// error
else {
// DLog(@"GlobalizationCommand getCurrencyPattern unable to get pattern for %@", currencyCode);
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"];
[dictionary setValue:@"Unable to get pattern" forKey:@"message"];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
}

[self.commandDelegate sendPluginResult:result callbackId:[command callbackId]];
}

- (void)dealloc
{
if (currentLocale) {
CFRelease(currentLocale);
currentLocale = nil;
}
}

@end