summaryrefslogtreecommitdiff
path: root/core.c
blob: 1f3ac670df7015cdf2330131acfb667313778701 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "core.h"
#include "database.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

void printError(const char *s) {
  printf("ERROR: %s\n", s);
}


void printInfo(const char *s) {
  printf("INFO: %s\n", s);
}

char* replaceChar(char* str, char find, char replace) {
  char *currentPos = strchr(str,find);
  while(currentPos) {
    *currentPos = replace;
    currentPos = strchr(currentPos, find);
  }
  return str;
}

void gitrolex_parseArgs(struct State_t *s, int argc, const char *argv[]) {
  const char *task;
  if(argc < 3) {
    s->task = ERROR;
    return;
  }
  task = argv[1];
  if(!strcmp(task, "status")) {
    s->task = STATUS;
  }
  else if(!strcmp(task, "export")) {
    s->task = EXPORT;
  }
  else if(!strcmp(task, "pause")) {
    s->task = PAUSE;
  }
  else if(!strcmp(task, "play")) {
    s->task = PLAY;
  }
  else if(!strcmp(task, "track")) {
    s->task = TRACK;
  }
  strcpy(s->taskArgs, argv[2]);
  // lame attempt at path sanitization
  replaceChar(s->taskArgs, '/', '-');
  replaceChar(s->taskArgs, '$', '-');
}

// TODO return a message/status such that we can test this
// (printing directly to the screen makes this hard)
enum Error_t gitrolex_status(struct State_t *s, bool force) {
  enum DatabaseError_t r;
  char msg[512];
  int size = 2048;
  struct TimeEnty_t entries[2048];
  const char *template = "You've been working on %s for %ld seconds";
  r = database_getEntries(s->taskArgs, entries, &size);
  if(r != OK || size <= 0) {
    printError("Failed to read from db");
    return OK;
  }
  else if (size == 1) {
    if(force) {
      sprintf(msg, template, s->taskArgs, time(NULL) - entries[0].datetime);
    }
    else {
      sprintf(msg, "Starting %s", s->taskArgs);
    }
  }
  else {
    long workingTime = gitrolex_calculateWorkingTime(entries, size);
    sprintf(msg, template, s->taskArgs, workingTime);
  }
  printInfo(msg);
  return OK;
}

long gitrolex_calculateWorkingTime(struct TimeEnty_t *t, int size) {
  if (size < 2) return -1;
  long sum;
  sum = 0;
  for(int i = 0; i < size - 1; i += 2) {
    struct TimeEnty_t *start = &t[i];
    struct TimeEnty_t *end = &t[i + 1];
    // we should always be taking the diff
    // between a checkout "e.g working on it" and a
    // check in "e.eg finishing work"
    if(start->direction != OUT || end->direction != IN) {
      return -1;
    }
    sum += end->datetime - start->datetime;
  }
  return sum;
}

enum Error_t pushNow(struct State_t *s, bool direction) {
  enum DatabaseError_t r;
  struct TimeEnty_t entry = {
    .direction = direction,
    .datetime = time(NULL)
  };
  r = database_pushEntry(s->taskArgs, &entry);
  gitrolex_status(s, false);
  return r == DB_OK ? OK : DB_ERROR;
}

enum Error_t gitrolex_checkout(struct State_t *s){
  return pushNow(s, OUT);
}

enum Error_t gitrolex_checkin(struct State_t *s){
  return pushNow(s, IN);
}

enum Error_t gitrolex_export(struct State_t *s) {
  return -1;
}


void gitrolex_mapStateToTask(struct State_t *s) {
  enum Error_t r;
  switch(s->task) {
    case STATUS:
      gitrolex_status(s, true);
      break;
    case EXPORT:
      r = gitrolex_export(s);
      break;
    case TRACK:
      r = gitrolex_checkout(s);
      break;
    case PAUSE:
      r = gitrolex_checkin(s);
      break;
    case PLAY:
      r = gitrolex_checkout(s);
      break;
    case ERROR:
    default:
      printError("Usage ./gitrolex status | export | pause | play | track <branch-name>");
      break;
  }
}

int gitrolex_core(int argc, const char* argv[]) {
  struct State_t state;
  gitrolex_parseArgs(&state, argc, argv);
  gitrolex_mapStateToTask(&state);
}