//
//  NSObject+UnformattedDescription.m
//  mulle-plist-from-files
//
//  Created by Nat! on 08.02.13.
//  Copyright (c) 2013 Nat!. All rights reserved.
//

#import "NSObject+UnformattedDescription.h"


@implementation NSObject ( UnformattedDescription)

- (NSString *) unformattedDescription
{
   return( [self description]);  // quote if needed
}

@end


@implementation NSDate ( UnformattedDescription)

- (NSString *) unformattedDescription
{
   NSString  *s;
   
   s = [self descriptionWithLocale:nil];
   return( [s unformattedDescription]);
}

@end


@implementation NSNumber ( UnformattedDescription)

- (NSString *) unformattedDescription
{
   NSString  *s;
   
   s = [self descriptionWithLocale:nil];
   return( [s unformattedDescription]);
}

@end


@implementation NSData ( UnformattedDescription)

- (BOOL) propertyListUTF8DataNeedsQuoting
{
   size_t          len;
   unsigned char   *s;
   unsigned char   *sentinel;
   
   len = [self length];
   if( ! len || len > 128)
      return( YES);
   
   s = (unsigned char *) [self bytes];

   sentinel = &s[ len];
   while( s < sentinel)
   {
      if( ! isalnum( *s) && *s != '_')
         return( YES);
      ++s;
   }
   return( NO);
}

@end


@implementation NSString ( UnformattedDescription)

- (NSData *) _propertyListUTF8Data
{
   NSData          *data;
   unsigned char   *s, *start;
   unsigned char   *q, *sentinel;
   size_t          len;
   NSMutableData   *target;
   
   data = [self dataUsingEncoding:NSUTF8StringEncoding];
   if( ! [data propertyListUTF8DataNeedsQuoting])
      return( data);
   
   // do proper quoting and escaping
   len    = [data length];
   target = [NSMutableData dataWithLength:len * 2 + 2];
   start  = (unsigned char *) [target mutableBytes];
   s      = start;
   q      = (unsigned char *) [data bytes];
   
   sentinel = &q[ len];
   *s++     = '\"';
   
   while( q < sentinel)
   {
      switch( *q)
      {
         default   : *s++ = *q; break;
         case '\a' : *s++ = '\\'; *s++ = 'a'; break;
         case '\b' : *s++ = '\\'; *s++ = 'b'; break;
         case '\f' : *s++ = '\\'; *s++ = 'f'; break;
         case '\n' : *s++ = '\\'; *s++ = 'n'; break;
         case '\r' : *s++ = '\\'; *s++ = 'r'; break;
         case '\t' : *s++ = '\\'; *s++ = 't'; break;
         case '\v' : *s++ = '\\'; *s++ = 'v'; break;
         case '\\' : *s++ = '\\'; *s++ = '\\'; break;
         case '\"' : *s++ = '\\'; *s++ = '\"'; break;
#if ESCAPED_ZERO_IN_UTF8_STRING_IS_A_GOOD_THING
         case 0    : *s++ = '\\'; *s++ = '0'; break;
#endif
      }
      ++q;
   }
   
   *s++   = '\"';
   
   [target setLength:s - start];
   return( target);
}


- (NSString *) unformattedDescription
{
   NSData   *data;
   
   data = [self _propertyListUTF8Data];
   return( [[[NSString alloc] initWithData:data
                                  encoding:NSUTF8StringEncoding] autorelease]);
}

@end


@implementation NSSet ( UnformattedDescription)

- (NSString *) unformattedDescription
{
   NSEnumerator      *rover;
   NSString          *description;
   id                value;
   NSMutableString   *output;
   
   output = [NSMutableString string];
   [output appendString:@"<("];
   
   rover = [self objectEnumerator];
   if( value = [rover nextObject])
   {
      description = [value unformattedDescription];
      [output appendFormat:@"%@", description];
   }
   while( value = [rover nextObject])
   {
      description = [value unformattedDescription];
      [output appendFormat:@",%@", description];
   }
   [output appendString:@")>"];
   
   return( output);
}

@end


@implementation NSArray ( UnformattedDescription)

- (NSString *) unformattedDescription
{
   NSEnumerator      *rover;
   NSString          *description;
   id                value;
   NSMutableString   *output;
   
   output = [NSMutableString string];
   [output appendString:@"("];
   
   rover = [self objectEnumerator];
   if( value = [rover nextObject])
   {
      description = [value unformattedDescription];
      [output appendFormat:@"%@", description];
   }
   while( value = [rover nextObject])
   {
      description = [value unformattedDescription];
      [output appendFormat:@",%@", description];
   }
   [output appendString:@")"];
   
   return( output);
}

@end


@implementation NSDictionary ( UnformattedDescription)

- (NSString *) unformattedDescription
{
   NSEnumerator      *rover;
   NSString          *key;
   NSString          *description;
   id                value;
   NSMutableString   *output;
   
   output = [NSMutableString string];
   [output appendString:@"{"];
   
   rover = [self keyEnumerator];
   while( key = [rover nextObject])
   {
      value       = [self objectForKey:key];
      description = [value unformattedDescription];
      [output appendFormat:@"%@=%@;", key, description];
   }
   [output appendString:@"}"];
   
   return( output);
}

@end