/*
 Erica Sadun, http://ericasadun.com
 iPhone Developer's Cookbook, 6.x Edition
 BSD License, Use at your own risk
 
 Modified by Eric Horacek for Monospace Ltd. on 2/4/13
 */

// 2015/09/05 AIG-Soft
// ここにある最新版に対し、古いバージョンの内容を追加したもの
// https://github.com/erichoracek/UIDevice-Hardware/blob/master/UIDevice-Hardware.m

// Thanks to Emanuele Vulcano, Kevin Ballard/Eridius, Ryandjohnson, Matt Brown, etc.

#include <sys/sysctl.h>
#import "UIDevice-Hardware.h"

@implementation UIDevice (Hardware)

#pragma mark sysctlbyname utils
- (NSString *) getSysInfoByName:(char *)typeSpecifier
{
    size_t size;
    sysctlbyname(typeSpecifier, NULL, &size, NULL, 0);
    
    char *answer = malloc(size);
    sysctlbyname(typeSpecifier, answer, &size, NULL, 0);
    
    NSString *results = @(answer);

    free(answer);
    return results;
}

- (NSString *) platform
{
    return [self getSysInfoByName:"hw.machine"];
}

// platformと同じ
- (NSString *)modelIdentifier
{
	return [self getSysInfoByName:"hw.machine"];
}

- (NSString *)modelName
{
	return [self modelNameForModelIdentifier:[self modelIdentifier]];
}

// Thanks, Tom Harrington (Atomicbird)
- (NSString *) hwmodel
{
    return [self getSysInfoByName:"hw.model"];
}

#pragma mark platform type and name utils

- (NSString *)modelNameForModelIdentifier:(NSString *)modelIdentifier
{
	// iPhone http://theiphonewiki.com/wiki/IPhone
	
	if ([modelIdentifier isEqualToString:@"iPhone1,1"])    return @"iPhone 1G";
	if ([modelIdentifier isEqualToString:@"iPhone1,2"])    return @"iPhone 3G";
	if ([modelIdentifier isEqualToString:@"iPhone2,1"])    return @"iPhone 3GS";
	if ([modelIdentifier isEqualToString:@"iPhone3,1"])    return @"iPhone 4 (GSM)";
	if ([modelIdentifier isEqualToString:@"iPhone3,2"])    return @"iPhone 4 (GSM Rev A)";
	if ([modelIdentifier isEqualToString:@"iPhone3,3"])    return @"iPhone 4 (CDMA)";
	if ([modelIdentifier isEqualToString:@"iPhone4,1"])    return @"iPhone 4S";
	if ([modelIdentifier isEqualToString:@"iPhone5,1"])    return @"iPhone 5 (GSM)";
	if ([modelIdentifier isEqualToString:@"iPhone5,2"])    return @"iPhone 5 (Global)";
	if ([modelIdentifier isEqualToString:@"iPhone5,3"])    return @"iPhone 5c (GSM)";
	if ([modelIdentifier isEqualToString:@"iPhone5,4"])    return @"iPhone 5c (Global)";
	if ([modelIdentifier isEqualToString:@"iPhone6,1"])    return @"iPhone 5s (GSM)";
	if ([modelIdentifier isEqualToString:@"iPhone6,2"])    return @"iPhone 5s (Global)";
	if ([modelIdentifier isEqualToString:@"iPhone7,1"])    return @"iPhone 6 Plus";
	if ([modelIdentifier isEqualToString:@"iPhone7,2"])    return @"iPhone 6";
	
	// iPad http://theiphonewiki.com/wiki/IPad
	
	if ([modelIdentifier isEqualToString:@"iPad1,1"])      return @"iPad 1";				// Gを削除
	if ([modelIdentifier isEqualToString:@"iPad2,1"])      return @"iPad 2 (Wi-Fi)";
	if ([modelIdentifier isEqualToString:@"iPad2,2"])      return @"iPad 2 (GSM)";
	if ([modelIdentifier isEqualToString:@"iPad2,3"])      return @"iPad 2 (CDMA)";
	if ([modelIdentifier isEqualToString:@"iPad2,4"])      return @"iPad 2 (Rev A)";
	if ([modelIdentifier isEqualToString:@"iPad3,1"])      return @"iPad 3 (Wi-Fi)";
	if ([modelIdentifier isEqualToString:@"iPad3,2"])      return @"iPad 3 (GSM)";
	if ([modelIdentifier isEqualToString:@"iPad3,3"])      return @"iPad 3 (Global)";
	if ([modelIdentifier isEqualToString:@"iPad3,4"])      return @"iPad 4 (Wi-Fi)";
	if ([modelIdentifier isEqualToString:@"iPad3,5"])      return @"iPad 4 (GSM)";
	if ([modelIdentifier isEqualToString:@"iPad3,6"])      return @"iPad 4 (Global)";
	
	if ([modelIdentifier isEqualToString:@"iPad4,1"])      return @"iPad Air 1 (Wi-Fi)";	// 1を追加
	if ([modelIdentifier isEqualToString:@"iPad4,2"])      return @"iPad Air 1 (Cellular)";	// 1を追加
	if ([modelIdentifier isEqualToString:@"iPad5,3"])      return @"iPad Air 2 (Wi-Fi)";
	if ([modelIdentifier isEqualToString:@"iPad5,4"])      return @"iPad Air 2 (Cellular)";
	
	// iPad Mini http://theiphonewiki.com/wiki/IPad_mini
	
	if ([modelIdentifier isEqualToString:@"iPad2,5"])      return @"iPad mini 1 (Wi-Fi)";	// Gを削除(以下すべて)
	if ([modelIdentifier isEqualToString:@"iPad2,6"])      return @"iPad mini 1 (GSM)";
	if ([modelIdentifier isEqualToString:@"iPad2,7"])      return @"iPad mini 1 (Global)";
	if ([modelIdentifier isEqualToString:@"iPad4,4"])      return @"iPad mini 2 (Wi-Fi)";
	if ([modelIdentifier isEqualToString:@"iPad4,5"])      return @"iPad mini 2 (Cellular)";
	if ([modelIdentifier isEqualToString:@"iPad4,7"])      return @"iPad mini 3 (Wi-Fi)";
	if ([modelIdentifier isEqualToString:@"iPad4,8"])      return @"iPad mini 3 (Cellular)";
	if ([modelIdentifier isEqualToString:@"iPad4,9"])      return @"iPad mini 3 (Cellular)";
	
	// iPod http://theiphonewiki.com/wiki/IPod
	
	if ([modelIdentifier isEqualToString:@"iPod1,1"])      return @"iPod touch 1";	// Gを削除(以下すべて)
	if ([modelIdentifier isEqualToString:@"iPod2,1"])      return @"iPod touch 2";
	if ([modelIdentifier isEqualToString:@"iPod3,1"])      return @"iPod touch 3";
	if ([modelIdentifier isEqualToString:@"iPod4,1"])      return @"iPod touch 4";
	if ([modelIdentifier isEqualToString:@"iPod5,1"])      return @"iPod touch 5";
	
	// Simulator
	if ([modelIdentifier hasSuffix:@"86"] || [modelIdentifier isEqual:@"x86_64"])
	{
		BOOL smallerScreen = ([[UIScreen mainScreen] bounds].size.width < 768.0);
		return (smallerScreen ? @"iPhone Simulator" : @"iPad Simulator");
	}
	
	return modelIdentifier;
}

- (UIDeviceFamily) deviceFamily
{
    NSString *platform = [self platform];
    if ([platform hasPrefix:@"iPhone"]) 	return UIDeviceFamilyiPhone;
    if ([platform hasPrefix:@"iPod"]) 		return UIDeviceFamilyiPod;
    if ([platform hasPrefix:@"iPad"]) 		return UIDeviceFamilyiPad;
    if ([platform hasPrefix:@"AppleTV"])	return UIDeviceFamilyAppleTV;
    return UIDeviceFamilyUnknown;
}

- (BOOL) hasRetinaDisplay
{
	return ([UIScreen mainScreen].scale == 2.0f);
}

#pragma mark sysctl utils
- (NSUInteger) getSysInfo: (uint) typeSpecifier
{
	size_t size = sizeof(int);
	int results;
	int mib[2] = {CTL_HW, typeSpecifier};
	sysctl(mib, 2, &results, &size, NULL, 0);
	return (NSUInteger) results;
}

// 以下は正しいかどうかわからない。何らかの数値は返ってきているが、実機でも正しいようには見えない。
- (NSUInteger) cpuFrequency
{
	return [self getSysInfo:HW_CPU_FREQ];
}

- (NSUInteger) busFrequency
{
	return [self getSysInfo:HW_BUS_FREQ];
}

- (NSUInteger) cpuCount
{
	return [self getSysInfo:HW_NCPU];
}

- (NSUInteger) totalMemory
{
	return [self getSysInfo:HW_PHYSMEM];
}

- (NSUInteger) userMemory
{
	return [self getSysInfo:HW_USERMEM];
}

#pragma mark file system -- Thanks Joachim Bean!

/*
 extern NSString *NSFileSystemSize;
 extern NSString *NSFileSystemFreeSize;
 extern NSString *NSFileSystemNodes;
 extern NSString *NSFileSystemFreeNodes;
 extern NSString *NSFileSystemNumber;
 */

- (NSNumber *) totalDiskSpace
{
	NSDictionary *fattributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil];
	return fattributes[NSFileSystemSize];
}

- (NSNumber *) freeDiskSpace
{
	NSDictionary *fattributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil];
	return fattributes[NSFileSystemFreeSize];
}

@end