Expanded open file functionality to use available apps.
[pithos-ios] / Classes / LoadBalancerViewController.m
1 //
2 //  LoadBalancerViewController.m
3 //  OpenStack
4 //
5 //  Created by Michael Mayo on 3/25/11.
6 //  Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "LoadBalancerViewController.h"
10 #import "LoadBalancer.h"
11 #import "LoadBalancerNode.h"
12 #import <QuartzCore/QuartzCore.h>
13 #import "LBTitleView.h"
14 #import "LoadBalancerProtocol.h"
15 #import "Server.h"
16 #import "ConfigureLoadBalancerViewController.h"
17 #import "OpenStackAccount.h"
18 #import "AccountManager.h"
19 #import "APICallback.h"
20 #import "LoadBalancerUsage.h"
21 #import "NSObject+Conveniences.h"
22 #import "VirtualIP.h"
23 #import "UIViewController+Conveniences.h"
24 #import "LBNodeViewController.h"
25 #import "Image.h"
26
27 #define kDetails 0
28 #define kNodes 1
29
30 #define kEnabled @"ENABLED"
31 #define kDisabled @"DISABLED"
32 #define kDraining @"DRAINING"
33
34 @implementation LoadBalancerViewController
35
36 @synthesize account, loadBalancer, tableView, titleView;
37
38 #pragma mark - Constructors and Memory Management
39
40 -(id)initWithLoadBalancer:(LoadBalancer *)lb {
41     self = [self initWithNibName:@"LoadBalancerViewController" bundle:nil];
42     if (self) {
43         self.loadBalancer = lb;
44         mode = kDetails;
45         nodes = [[NSMutableDictionary alloc] init];
46     }
47     return self;
48 }
49
50 - (void)dealloc {
51     [account release];
52     [loadBalancer release];
53     [tableView release];
54     [titleView release];
55     [nodes release];
56     [super dealloc];
57 }
58
59 #pragma mark - Utilities
60
61 - (LoadBalancerNode *)nodeForIndexPath:(NSIndexPath *)indexPath {
62     LoadBalancerNode *node = nil;    
63     if (indexPath.section == enabledSection) {
64         node = [[nodes objectForKey:kEnabled] objectAtIndex:indexPath.row];
65     } else if (indexPath.section == drainingSection) {
66         node = [[nodes objectForKey:kDraining] objectAtIndex:indexPath.row];
67     } else if (indexPath.section == disabledSection) {
68         node = [[nodes objectForKey:kDisabled] objectAtIndex:indexPath.row];
69     }
70     return node;
71 }
72
73 - (void)pollLoadBalancer {
74     NSString *endpoint = [self.account loadBalancerEndpointForRegion:self.loadBalancer.region];    
75     [[self.account.manager getLoadBalancerDetails:self.loadBalancer endpoint:endpoint] success:^(OpenStackRequest *request) {
76         self.titleView.statusDot.image = [self.loadBalancer imageForStatus];
77         if ([self.loadBalancer shouldBePolled]) {
78             [self pollLoadBalancer];
79         }
80     } failure:^(OpenStackRequest *request) {
81     }];
82 }
83
84 #pragma mark - View lifecycle
85
86 - (void)viewDidLoad {
87     [super viewDidLoad];
88     self.navigationItem.title = @"Load Balancer";
89     previousScrollPoint = CGPointZero;
90     
91     if (!titleView) {        
92         titleView = [[LBTitleView alloc] initWithLoadBalancer:self.loadBalancer];
93         [self.view addSubview:titleView];
94         [titleView setNeedsDisplay];
95     }    
96
97     // Uncomment the following line to preserve selection between presentations.
98     // self.clearsSelectionOnViewWillAppear = NO;
99  
100     // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
101     //self.navigationItem.rightBarButtonItem = self.editButtonItem;
102     UIBarButtonItem *configure = [[UIBarButtonItem alloc] initWithTitle:@"Configure" style:UIBarButtonItemStyleBordered target:self action:@selector(configButtonPressed:)];
103     self.navigationItem.rightBarButtonItem = configure;
104     [configure release];
105 }
106
107 - (void)viewDidUnload {
108     [super viewDidUnload];
109     self.tableView = nil;
110 }
111
112 - (void)viewWillAppear:(BOOL)animated {
113     [super viewWillAppear:animated];
114     
115     NSString *endpoint = [self.account loadBalancerEndpointForRegion:self.loadBalancer.region];
116     
117     [self showToolbarActivityMessage:@"Loading nodes..."];
118     
119     [[self.account.manager getLoadBalancerDetails:self.loadBalancer endpoint:endpoint] success:^(OpenStackRequest *request) {
120
121         [self hideToolbarActivityMessage];
122
123         // break up nodes by condition into ENABLED, DISABLED, and DRAINING
124         [nodes setObject:[NSMutableArray array] forKey:kEnabled];
125         [nodes setObject:[NSMutableArray array] forKey:kDisabled];
126         [nodes setObject:[NSMutableArray array] forKey:kDraining];
127         
128         for (LoadBalancerNode *node in loadBalancer.nodes) {
129             if ([node.condition isEqualToString:kEnabled]) {
130                 [[nodes objectForKey:kEnabled] addObject:node];
131             } else if ([node.condition isEqualToString:kDisabled]) {
132                 [[nodes objectForKey:kDisabled] addObject:node];
133             } else if ([node.condition isEqualToString:kDraining]) {
134                 [[nodes objectForKey:kDraining] addObject:node];
135             }                
136         }
137         
138         // sort each node group alphabetically
139         NSArray *sortedEnabled = [[nodes objectForKey:kEnabled] sortedArrayUsingSelector:@selector(compare:)];
140         NSArray *sortedDisabled = [[nodes objectForKey:kDisabled] sortedArrayUsingSelector:@selector(compare:)];
141         NSArray *sortedDraining = [[nodes objectForKey:kDraining] sortedArrayUsingSelector:@selector(compare:)];
142         [nodes setObject:[NSMutableArray arrayWithArray:sortedEnabled] forKey:kEnabled];
143         [nodes setObject:[NSMutableArray arrayWithArray:sortedDisabled] forKey:kDisabled];
144         [nodes setObject:[NSMutableArray arrayWithArray:sortedDraining] forKey:kDraining];
145         
146         totalSections = 0;
147         if ([[nodes objectForKey:kEnabled] count] > 0) {
148             enabledSection = totalSections++;
149         }
150         if ([[nodes objectForKey:kDisabled] count] > 0) {
151             disabledSection = totalSections++;
152         }
153         if ([[nodes objectForKey:kDraining] count] > 0) {
154             drainingSection = totalSections++;
155         }
156         
157         [self.tableView reloadData];
158     } failure:^(OpenStackRequest *request) {
159         [self hideToolbarActivityMessage];
160         [self alert:@"There was a problem loading information for this load balancer." request:request];
161     }];
162     
163     [[self.account.manager getLoadBalancerUsage:self.loadBalancer endpoint:endpoint] success:^(OpenStackRequest *request) {
164         self.titleView.connectedLabel.text = [NSString stringWithFormat:@"%.0f connected", self.loadBalancer.usage.averageNumConnections];
165         self.titleView.bwInLabel.text = [NSString stringWithFormat:@"%@ in", [LoadBalancerUsage humanizedBytes:self.loadBalancer.usage.incomingTransfer]];
166         self.titleView.bwOutLabel.text = [NSString stringWithFormat:@"%@ out", [LoadBalancerUsage humanizedBytes:self.loadBalancer.usage.outgoingTransfer]];
167     } failure:^(OpenStackRequest *request) {
168         self.titleView.connectedLabel.text = @"";
169         self.titleView.bwInLabel.text = @"";
170         self.titleView.bwOutLabel.text = @"";
171     }];
172     
173     if ([self.loadBalancer shouldBePolled]) {
174         [self pollLoadBalancer];
175     }
176 }
177
178 - (void)viewDidAppear:(BOOL)animated {
179     [super viewDidAppear:animated];    
180 }
181
182 - (void)viewWillDisappear:(BOOL)animated {
183     [super viewWillDisappear:animated];
184 }
185
186 - (void)viewDidDisappear:(BOOL)animated {
187     [super viewDidDisappear:animated];
188 }
189
190 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
191     return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (interfaceOrientation == UIInterfaceOrientationPortrait);
192 }
193
194 #pragma mark - Table view data source
195
196 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
197     return totalSections;
198 }
199
200 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
201     if (section == enabledSection) {
202         return [[nodes objectForKey:kEnabled] count];
203     } else if (section == drainingSection) {
204         return [[nodes objectForKey:kDraining] count];
205     } else if (section == disabledSection) {
206         return [[nodes objectForKey:kDisabled] count];
207     } else {
208         return 0;
209     }
210 }
211
212 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
213     if (section == enabledSection) {
214         return @"Enabled Nodes";
215     } else if (section == disabledSection) {
216         return @"Disabled Nodes";
217     } else if (section == drainingSection) {
218         return @"Draining Nodes";
219     } else {
220         return @"";
221     }
222 }
223
224 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    
225     static NSString *CellIdentifier = @"Cell";
226     
227     UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
228     if (cell == nil) {
229         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
230         cell.textLabel.backgroundColor = [UIColor clearColor];
231         cell.detailTextLabel.backgroundColor = [UIColor clearColor];
232         cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
233     }
234
235     LoadBalancerNode *node = [self nodeForIndexPath:indexPath];
236     
237     if (node.server) {
238         Server *server = node.server;
239         cell.textLabel.text = server.name;
240         cell.detailTextLabel.text = node.address;
241         if ([server.image respondsToSelector:@selector(logoPrefix)]) {
242             if ([[server.image logoPrefix] isEqualToString:kCustomImage]) {
243                 cell.imageView.image = [UIImage imageNamed:kCloudServersIcon];
244             } else {
245                 cell.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-icon.png", [server.image logoPrefix]]];
246             }
247         }
248     } else {
249         cell.textLabel.text = [NSString stringWithFormat:@"%@:%@", node.address, node.port];
250         cell.detailTextLabel.text = @"";
251         cell.imageView.image = nil;
252     }
253     
254         
255     return cell;
256 }
257
258 #pragma mark - Table view delegate
259
260 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
261     LoadBalancerNode *node = [self nodeForIndexPath:indexPath];
262     LBNodeViewController *vc = [[LBNodeViewController alloc] initWithNode:node loadBalancer:self.loadBalancer account:self.account];
263     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
264         vc.lbViewController = self;
265         vc.lbIndexPath = indexPath;
266         [self presentModalViewControllerWithNavigation:vc];
267     } else {
268         [self.navigationController pushViewController:vc animated:YES];
269     }    
270     [vc release];
271 }
272
273 #pragma mark - Button Handlers
274
275 - (void)configButtonPressed:(id)sender {
276     
277     if ([self.loadBalancer shouldBePolled]) {
278         [self alert:nil message:@"This load balancer can not be changed until it is in an active state."];
279     } else {
280         ConfigureLoadBalancerViewController *vc = [[ConfigureLoadBalancerViewController alloc] initWithAccount:self.account loadBalancer:self.loadBalancer];
281         vc.loadBalancerViewController = self;
282         [self presentModalViewControllerWithNavigation:vc];
283         [vc release];
284     }
285 }
286
287 @end