Expanded open file functionality to use available apps.
[pithos-ios] / Classes / ConfigureLoadBalancerViewController.m
1 //
2 //  ConfigureLoadBalancerViewController.m
3 //  OpenStack
4 //
5 //  Created by Mike Mayo on 6/22/11.
6 //  Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "ConfigureLoadBalancerViewController.h"
10 #import "LoadBalancer.h"
11 #import "LBProtocolViewController.h"
12 #import "OpenStackAccount.h"
13 #import "AccountManager.h"
14 #import "RSTextFieldCell.h"
15 #import "LBNodesViewController.h"
16 #import "LBAlgorithmViewController.h"
17 #import "AddLoadBalancerAlgorithmViewController.h"
18 #import "LoadBalancerProtocol.h"
19 #import "UIViewController+Conveniences.h"
20 #import "OpenStackRequest.h"
21 #import "APICallback.h"
22 #import "UIColor+MoreColors.h"
23 #import "VirtualIP.h"
24 #import "Analytics.h"
25 #import "PingIPAddressViewController.h"
26 #import "LoadBalancersViewController.h"
27 #import "LoadBalancerViewController.h"
28
29 #define kDetailsSection 0
30 #define kRegionSection 1
31 #define kVirtualIPsSection 2
32 #define kNodesSection 3
33 #define kConnectionLoggingSection 4
34 #define kDeleteSection 5
35
36 #define kName 0
37 #define kProtocol 1
38 #define kAlgorithm 2
39
40 #define kVirtualIPType 0
41 #define kRegion 1
42
43 @implementation ConfigureLoadBalancerViewController
44
45 @synthesize account, loadBalancer, loadBalancerViewController;
46
47 - (id)initWithAccount:(OpenStackAccount *)a loadBalancer:(LoadBalancer *)lb {
48     self = [super initWithStyle:UITableViewStyleGrouped];
49     if (self) {
50         self.account = a;
51         self.loadBalancer = lb;
52     }
53     return self;
54 }
55
56 - (void)dealloc {
57     [account release];
58     [loadBalancer release];
59     [algorithmNames release];
60     [deleteActionSheet release];
61     [ipActionSheet release];
62     [loadBalancerViewController release];
63     [super dealloc];
64 }
65
66 #pragma mark - View lifecycle
67
68 - (void)viewDidLoad {
69     [super viewDidLoad];
70     self.navigationItem.title = @"Configure";
71     [self addSaveButton];
72     
73 //    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
74         [self addCancelButton];
75 //    }
76     
77     algorithmNames = [[NSDictionary alloc] initWithObjectsAndKeys:
78                       @"Random",@"RANDOM", 
79                       @"Round Robin", @"ROUND_ROBIN", 
80                       @"Weighted Round Robin", @"WEIGHTED_ROUND_ROBIN", 
81                       @"Least Connections", @"LEAST_CONNECTIONS", 
82                       @"Weighted Least Connections", @"WEIGHTED_LEAST_CONNECTIONS", 
83                       nil];
84     
85     ipActionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Ping IP Address", @"Copy to Pasteboard", @"Open in Safari", nil];
86     deleteActionSheet = [[UIActionSheet alloc] initWithTitle:@"Are you sure you want to delete this load balancer?  This operation cannot be undone." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete Load Balancer" otherButtonTitles:nil];
87 }
88
89 - (void)viewWillAppear:(BOOL)animated {
90     [super viewWillAppear:animated];
91 }
92
93 - (void)viewDidAppear:(BOOL)animated {
94     [super viewDidAppear:animated];
95     [self.tableView reloadData];
96 }
97
98 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
99     return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
100 }
101
102 #pragma mark - Table view data source
103
104 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
105     return 6;
106 }
107
108 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
109     if (section == kDetailsSection) {
110         return 3;
111     } else if (section == kRegionSection) {
112         return 2;
113     } else if (section == kVirtualIPsSection) {
114         return [self.loadBalancer.virtualIPs count];
115     } else {
116         return 1;
117     }
118 }
119
120 - (UITableViewCell *)nameCell:(UITableView *)tableView {
121     static NSString *CellIdentifier = @"NameCell";
122     
123     RSTextFieldCell *cell = (RSTextFieldCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
124     if (cell == nil) {
125         cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
126         cell.textLabel.text = @"Name";
127         cell.textField.delegate = self;
128     }
129     
130     cell.textField.text = self.loadBalancer.name;
131     
132     return cell;
133 }
134
135 - (UITableViewCell *)connectionLoggingCell:(UITableView *)tableView {
136     static NSString *CellIdentifier = @"ConnectionLoggingCell";
137     
138     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
139     if (cell == nil) {
140         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
141         cell.textLabel.text = @"Connection Logging";
142         cell.selectionStyle = UITableViewCellSelectionStyleNone;
143         
144         UISwitch *clSwitch = [[UISwitch alloc] init];
145         clSwitch.on = self.loadBalancer.connectionLoggingEnabled;
146         [clSwitch addTarget:self action:@selector(connectionLoggingSwitchChanged:) forControlEvents:UIControlEventValueChanged];
147         cell.accessoryView = clSwitch;
148         [clSwitch release];
149     }
150     
151     NSLog(@"self.loadBalancer.connectionLoggingEnabled = %i", self.loadBalancer.connectionLoggingEnabled);
152     ((UISwitch *)cell.accessoryView).on = self.loadBalancer.connectionLoggingEnabled;
153     
154     return cell;
155 }
156
157 - (UITableViewCell *)deleteCell:(UITableView *)tableView {
158     static NSString *CellIdentifier = @"DeleteCell";
159     
160     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
161     if (cell == nil) {
162         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
163         cell.textLabel.text = @"Delete Load Balancer";
164         cell.textLabel.textAlignment = UITextAlignmentCenter;
165         cell.textLabel.textColor = [UIColor value1DetailTextLabelColor];
166     }
167     return cell;
168 }
169
170 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
171     if (indexPath.section == kDetailsSection && indexPath.row == kName) {
172         return [self nameCell:tableView];
173     } else if (indexPath.section == kConnectionLoggingSection) {
174         return [self connectionLoggingCell:tableView];
175     } else if (indexPath.section == kDeleteSection) {
176         return [self deleteCell:tableView];
177     } else if (indexPath.section == kDetailsSection) {
178         static NSString *CellIdentifier = @"Cell";
179         
180         UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
181         if (cell == nil) {
182             cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
183             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
184         }
185         
186         switch (indexPath.row) {
187             case kProtocol:
188                 cell.textLabel.text = @"Protocol";
189                 cell.detailTextLabel.text = [NSString stringWithFormat:@"%@:%i", self.loadBalancer.protocol.name, self.loadBalancer.protocol.port];
190                 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
191                 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
192                 break;
193             case kAlgorithm:
194                 cell.textLabel.text = @"Algorithm";
195                 cell.detailTextLabel.text = [algorithmNames objectForKey:self.loadBalancer.algorithm];
196                 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
197                 cell.selectionStyle = UITableViewCellSelectionStyleBlue;
198                 break;
199             default:
200                 break;
201         }
202         
203         
204         return cell;
205     } else if (indexPath.section == kRegionSection) {
206         static NSString *CellIdentifier = @"RegionCell";
207         
208         UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
209         if (cell == nil) {
210             cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
211             cell.accessoryType = UITableViewCellAccessoryNone;
212             cell.selectionStyle = UITableViewCellSelectionStyleNone;
213         }
214         
215         switch (indexPath.row) {
216             case kVirtualIPType:
217                 cell.textLabel.text = @"Virtual IP Type";
218                 cell.detailTextLabel.text = self.loadBalancer.virtualIPType;
219                 break;
220             case kRegion:
221                 cell.textLabel.text = @"Region";
222                 cell.detailTextLabel.text = self.loadBalancer.region;
223                 break;
224             default:
225                 break;
226         }
227         
228         return cell;
229         
230     } else if (indexPath.section == kVirtualIPsSection) {
231         static NSString *CellIdentifier = @"VIPCell";
232         
233         UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
234         if (cell == nil) {
235             cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
236             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
237         }
238         
239         VirtualIP *vip = [self.loadBalancer.virtualIPs objectAtIndex:indexPath.row];        
240         cell.textLabel.text = [vip.type capitalizedString];
241         cell.detailTextLabel.text = vip.address;
242         
243         return cell;
244     } else {
245         static NSString *CellIdentifier = @"NodeCell";
246         
247         UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
248         if (cell == nil) {
249             cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
250             cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
251         }
252         
253         cell.textLabel.text = @"Nodes";
254         
255         if ([self.loadBalancer.nodes count] == 1) {
256             cell.detailTextLabel.text = @"1 Node";
257         } else {
258             cell.detailTextLabel.text = [NSString stringWithFormat:@"%i Nodes", [self.loadBalancer.nodes count]];
259         }
260         
261         return cell;
262     }
263 }
264
265 #pragma mark - Table view delegate
266
267 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
268     if (indexPath.section == kVirtualIPsSection) {
269         VirtualIP *vip = [self.loadBalancer.virtualIPs objectAtIndex:indexPath.row];
270         selectedVirtualIP = vip;
271         selectedVIPIndexPath = indexPath;        
272         ipActionSheet.title = vip.address;
273         [ipActionSheet showInView:self.view];
274     } else if (indexPath.section == kNodesSection) {
275         LBNodesViewController *vc = [[LBNodesViewController alloc] initWithNibName:@"LBNodesViewController" bundle:nil];
276         vc.isNewLoadBalancer = NO;
277         vc.account = self.account;
278         vc.loadBalancer = self.loadBalancer;
279         [self.navigationController pushViewController:vc animated:YES];
280         [vc release];        
281     } else if (indexPath.section == kDeleteSection) {
282         [deleteActionSheet showInView:self.view];
283     } else if (indexPath.section == kDetailsSection) {
284         if (indexPath.row == kProtocol) {
285             LBProtocolViewController *vc = [[LBProtocolViewController alloc] initWithAccount:self.account loadBalancer:self.loadBalancer];
286             [self.navigationController pushViewController:vc animated:YES];
287             [vc release];
288         } else if (indexPath.row == kAlgorithm) {
289             LBAlgorithmViewController *vc = [[LBAlgorithmViewController alloc] initWithLoadBalancer:self.loadBalancer];
290             [self.navigationController pushViewController:vc animated:YES];
291             [vc release];
292         }
293     }
294 }
295
296 #pragma mark - Action Sheet Delegate
297
298 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
299     if (actionSheet == deleteActionSheet) {
300         if (buttonIndex == 0) {            
301             [[self.account.manager deleteLoadBalancer:self.loadBalancer] success:^(OpenStackRequest *request) {                
302                 LoadBalancersViewController *vc = [[self.loadBalancerViewController.navigationController viewControllers] objectAtIndex:2];                
303                 [vc refreshButtonPressed:nil];
304                 [self dismissModalViewControllerAnimated:YES];
305                 [self.loadBalancerViewController.navigationController popToViewController:vc animated:YES];
306             } failure:^(OpenStackRequest *request) {
307                 [self alert:@"There was a problem deleting the load balancer." request:request];
308             }];
309         }
310         NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:kDeleteSection];
311         [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
312     } else if (actionSheet == ipActionSheet) {
313         if (buttonIndex == 0) { // ping
314             TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_PINGED);            
315             PingIPAddressViewController *vc = [[PingIPAddressViewController alloc] initWithNibName:@"PingIPAddressViewController" bundle:nil ipAddress:selectedVirtualIP.address];
316             if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
317                 vc.modalPresentationStyle = UIModalPresentationPageSheet;
318             }                
319             [self.navigationController presentModalViewController:vc animated:YES];
320             [vc release];
321         } else if (buttonIndex == 1) { // copy to pasteboard
322             UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
323             [pasteboard setString:selectedVirtualIP.address];
324             [self.tableView deselectRowAtIndexPath:selectedVIPIndexPath animated:YES];
325         } else if (buttonIndex == 2) { // open in safari
326             UIApplication *application = [UIApplication sharedApplication];
327             NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", selectedVirtualIP.address]];
328             if ([application canOpenURL:url]) {
329                 [application openURL:url];
330             }
331         }
332         [self.tableView deselectRowAtIndexPath:selectedVIPIndexPath animated:YES];
333     }
334 }
335
336 #pragma mark - Text field delegate
337
338 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
339     self.loadBalancer.name = [textField.text stringByReplacingCharactersInRange:range withString:string];
340     return YES;
341 }
342
343 - (BOOL)textFieldShouldReturn:(UITextField *)textField {
344     [textField resignFirstResponder];
345     return NO;
346 }
347
348 #pragma mark - Button Handlers
349
350 - (void)saveButtonPressed:(id)sender {
351     [[self.account.manager updateLoadBalancer:self.loadBalancer] success:^(OpenStackRequest *request) {
352         [self dismissModalViewControllerAnimated:YES];
353     } failure:^(OpenStackRequest *request) {
354         [self alert:@"There was a problem updating this load balancer." request:request];
355     }];
356 }
357
358 - (void)cancelButtonPressed:(id)sender {
359     [self dismissModalViewControllerAnimated:YES];
360 }
361
362 #pragma mark - Connection Logging Switch
363
364 - (void)connectionLoggingSwitchChanged:(UISwitch *)sender {
365     self.loadBalancer.connectionLoggingEnabled = sender.on;
366     [[self.account.manager updateLoadBalancerConnectionLogging:self.loadBalancer] success:^(OpenStackRequest *request) { 
367     } failure:^(OpenStackRequest *request) {
368         [self alert:@"There was a problem updating the load balancer." request:request];
369     }];
370 }
371
372 @end